@adia-ai/web-components 0.8.39 → 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.
- package/CHANGELOG.md +59 -0
- package/MIGRATION.md +1269 -3
- package/README.md +25 -30
- package/USAGE.md +26 -0
- package/bin/audit-template-children.mjs +556 -0
- package/components/accordion/accordion-item.a2ui.json +4 -0
- package/components/accordion/accordion-item.yaml +2 -0
- package/components/accordion/accordion.a2ui.json +4 -0
- package/components/accordion/accordion.yaml +2 -0
- package/components/action-list/action-item.a2ui.json +24 -2
- package/components/action-list/action-item.yaml +28 -3
- package/components/action-list/action-list.a2ui.json +6 -1
- package/components/action-list/action-list.class.js +52 -11
- package/components/action-list/action-list.css +43 -3
- package/components/action-list/action-list.d.ts +4 -2
- package/components/action-list/action-list.yaml +5 -0
- package/components/adia-mark/adia-mark.a2ui.json +1 -0
- package/components/adia-wordmark/adia-wordmark.a2ui.json +1 -0
- package/components/agent-artifact/agent-artifact.a2ui.json +1 -0
- package/components/agent-artifact/agent-artifact.css +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.a2ui.json +6 -5
- package/components/agent-feedback-bar/agent-feedback-bar.yaml +6 -2
- package/components/agent-questions/agent-questions.a2ui.json +1 -0
- package/components/agent-reasoning/agent-reasoning.a2ui.json +6 -5
- package/components/agent-reasoning/agent-reasoning.css +2 -2
- package/components/agent-reasoning/agent-reasoning.yaml +6 -2
- package/components/agent-suggestions/agent-suggestions.a2ui.json +11 -2
- package/components/agent-suggestions/agent-suggestions.class.js +2 -1
- package/components/agent-suggestions/agent-suggestions.d.ts +4 -4
- package/components/agent-suggestions/agent-suggestions.yaml +4 -2
- package/components/agent-trace/agent-trace.a2ui.json +6 -5
- package/components/agent-trace/agent-trace.css +3 -3
- package/components/agent-trace/agent-trace.yaml +6 -2
- package/components/alert/alert.a2ui.json +1 -0
- package/components/alert/alert.css +2 -2
- package/components/anchor-bar/anchor-bar.a2ui.json +1 -0
- package/components/aside/aside.a2ui.json +1 -0
- package/components/avatar/avatar-group.a2ui.json +7 -1
- package/components/avatar/avatar-group.yaml +1 -0
- package/components/avatar/avatar.a2ui.json +12 -11
- package/components/avatar/avatar.css +1 -1
- package/components/avatar/avatar.d.ts +1 -1
- package/components/avatar/avatar.yaml +4 -4
- package/components/badge/badge.a2ui.json +1 -0
- package/components/badge/badge.css +1 -1
- package/components/block/block.a2ui.json +1 -0
- package/components/blockquote/blockquote.a2ui.json +1 -0
- package/components/breadcrumb/breadcrumb.a2ui.json +1 -0
- package/components/button/button.a2ui.json +1 -3
- package/components/button/button.css +6 -5
- package/components/button/button.yaml +1 -3
- package/components/calendar-grid/calendar-grid.a2ui.json +1 -0
- package/components/calendar-grid/calendar-grid.class.js +2 -1
- package/components/calendar-picker/calendar-picker.a2ui.json +143 -24
- package/components/calendar-picker/calendar-picker.class.js +490 -197
- package/components/calendar-picker/calendar-picker.css +121 -172
- package/components/calendar-picker/calendar-picker.yaml +225 -47
- package/components/canvas/canvas.a2ui.json +6 -5
- package/components/canvas/canvas.d.ts +37 -0
- package/components/canvas/canvas.js +72 -3
- package/components/canvas/canvas.yaml +6 -2
- package/components/card/card.a2ui.json +25 -2
- package/components/card/card.class.js +3 -0
- package/components/card/card.css +34 -4
- package/components/card/card.d.ts +2 -2
- package/components/card/card.examples.md +3 -3
- package/components/card/card.yaml +28 -4
- package/components/chart/chart.a2ui.json +13 -8
- package/components/chart/chart.class.js +10 -10
- package/components/chart/chart.css +12 -10
- package/components/chart/chart.d.ts +2 -2
- package/components/chart/chart.yaml +8 -5
- package/components/chart-legend/chart-legend.a2ui.json +1 -0
- package/components/chat-thread/chat-input.a2ui.json +1 -0
- package/components/chat-thread/chat-thread.a2ui.json +10 -9
- package/components/chat-thread/chat-thread.css +1 -1
- package/components/chat-thread/chat-thread.yaml +13 -20
- package/components/check/check.a2ui.json +10 -9
- package/components/check/check.yaml +4 -4
- package/components/code/code.a2ui.json +1 -0
- package/components/code/code.css +6 -6
- package/components/col/col.a2ui.json +1 -0
- package/components/color-input/color-input.a2ui.json +1 -0
- package/components/color-picker/color-picker.a2ui.json +1 -0
- package/components/combobox/combobox.a2ui.json +3 -2
- package/components/combobox/combobox.css +2 -2
- package/components/combobox/combobox.yaml +2 -2
- package/components/command/command.a2ui.json +12 -10
- package/components/command/command.class.js +3 -2
- package/components/command/command.css +3 -3
- package/components/command/command.yaml +17 -4
- package/components/context-menu/context-menu.a2ui.json +1 -0
- package/components/date-range-picker/date-range-picker.a2ui.json +2 -1
- package/components/date-range-picker/date-range-picker.css +1 -1
- package/components/date-range-picker/date-range-picker.yaml +1 -1
- package/components/datetime-picker/datetime-picker.a2ui.json +15 -108
- package/components/datetime-picker/datetime-picker.class.js +37 -690
- package/components/datetime-picker/datetime-picker.css +11 -183
- package/components/datetime-picker/datetime-picker.d.ts +4 -5
- package/components/datetime-picker/datetime-picker.yaml +44 -135
- package/components/demo-toggle/demo-toggle.a2ui.json +1 -0
- package/components/demo-toggle/demo-toggle.css +1 -1
- package/components/description-list/description-list.a2ui.json +1 -0
- package/components/description-list/description-list.css +2 -2
- package/components/display-field/display-field.a2ui.json +1 -0
- package/components/display-field/display-field.css +3 -3
- package/components/divider/divider.a2ui.json +1 -0
- package/components/divider/divider.css +1 -1
- package/components/drawer/drawer.a2ui.json +1 -3
- package/components/drawer/drawer.css +3 -3
- package/components/drawer/drawer.yaml +0 -2
- package/components/drilldown/drilldown.a2ui.json +22 -20
- package/components/drilldown/drilldown.class.js +4 -3
- package/components/drilldown/drilldown.css +8 -8
- package/components/drilldown/drilldown.yaml +40 -9
- package/components/embed/embed.a2ui.json +6 -5
- package/components/embed/embed.yaml +2 -2
- package/components/empty-state/empty-state.a2ui.json +1 -0
- package/components/empty-state/empty-state.css +2 -2
- package/components/feed/feed-item.a2ui.json +25 -5
- package/components/feed/feed-item.yaml +28 -7
- package/components/feed/feed.a2ui.json +9 -2
- package/components/feed/feed.class.js +19 -12
- package/components/feed/feed.css +8 -8
- package/components/feed/feed.yaml +14 -1
- package/components/field/field.a2ui.json +1 -0
- package/components/field/field.css +1 -1
- package/components/field/field.examples.md +1 -1
- package/components/fields/fields.a2ui.json +1 -0
- package/components/fields/fields.examples.md +1 -1
- package/components/footer/footer.a2ui.json +1 -0
- package/components/frame/frame.a2ui.json +1 -0
- package/components/grid/grid.a2ui.json +1 -0
- package/components/header/header.a2ui.json +3 -2
- package/components/header/header.yaml +3 -3
- package/components/heatmap/heatmap.a2ui.json +2 -1
- package/components/heatmap/heatmap.class.js +1 -1
- package/components/heatmap/heatmap.css +6 -6
- package/components/heatmap/heatmap.yaml +1 -1
- package/components/icon/icon.a2ui.json +1 -0
- package/components/image/image.a2ui.json +28 -14
- package/components/image/image.class.js +38 -23
- package/components/image/image.css +18 -8
- package/components/image/image.d.ts +2 -2
- package/components/image/image.examples.md +3 -3
- package/components/image/image.yaml +23 -7
- package/components/inline-edit/inline-edit.a2ui.json +1 -0
- package/components/inline-message/inline-message.a2ui.json +3 -1
- package/components/inline-message/inline-message.class.js +3 -1
- package/components/inline-message/inline-message.css +1 -1
- package/components/inline-message/inline-message.d.ts +2 -2
- package/components/inline-message/inline-message.yaml +2 -1
- package/components/input/input.a2ui.json +66 -16
- package/components/input/input.class.js +64 -7
- package/components/input/input.css +19 -18
- package/components/input/input.d.ts +9 -4
- package/components/input/input.yaml +83 -10
- package/components/inspector/inspector.a2ui.json +1 -0
- package/components/integration-card/integration-card.a2ui.json +1 -0
- package/components/integration-card/integration-card.css +4 -4
- package/components/kbd/kbd.a2ui.json +1 -0
- package/components/kbd/kbd.css +1 -1
- package/components/link/link.a2ui.json +2 -1
- package/components/link/link.yaml +1 -1
- package/components/list/list-item.a2ui.json +9 -0
- package/components/list/list-item.yaml +12 -0
- package/components/list/list.a2ui.json +9 -3
- package/components/list/list.class.js +14 -1
- package/components/list/list.css +14 -3
- package/components/list/list.d.ts +7 -5
- package/components/list/list.yaml +16 -6
- package/components/list-window/list-window.a2ui.json +1 -0
- package/components/list-window/list-window.class.js +2 -1
- package/components/loading-overlay/loading-overlay.a2ui.json +1 -0
- package/components/mark/mark.a2ui.json +2 -1
- package/components/mark/mark.yaml +1 -1
- package/components/menu/menu-divider.a2ui.json +1 -0
- package/components/menu/menu-item.a2ui.json +3 -1
- package/components/menu/menu-item.yaml +6 -0
- package/components/menu/menu-label.a2ui.json +1 -0
- package/components/menu/menu.a2ui.json +3 -2
- package/components/menu/menu.class.js +2 -2
- package/components/menu/menu.d.ts +2 -2
- package/components/menu/menu.yaml +3 -3
- package/components/modal/modal.a2ui.json +1 -0
- package/components/nav/nav.a2ui.json +1 -0
- package/components/nav/nav.class.js +14 -3
- package/components/nav/nav.css +2 -2
- package/components/nav-group/nav-group.a2ui.json +1 -0
- package/components/nav-group/nav-group.class.js +3 -1
- package/components/nav-group/nav-group.css +3 -3
- package/components/nav-item/nav-item.a2ui.json +1 -0
- package/components/nav-item/nav-item.css +2 -2
- package/components/noodles/noodles.a2ui.json +1 -0
- package/components/noodles/noodles.class.js +5 -1
- package/components/number-format/number-format.a2ui.json +1 -0
- package/components/option-card/option-card.a2ui.json +1 -0
- package/components/option-card/option-card.css +1 -1
- package/components/otp-input/otp-input.a2ui.json +3 -2
- package/components/otp-input/otp-input.css +1 -1
- package/components/otp-input/otp-input.yaml +9 -2
- package/components/page/page.a2ui.json +13 -0
- package/components/page/page.css +2 -2
- package/components/page/page.d.ts +1 -1
- package/components/page/page.yaml +1 -0
- package/components/pagination/pagination.a2ui.json +1 -0
- package/components/pagination/pagination.class.js +3 -2
- package/components/pagination/pagination.css +1 -1
- package/components/pane/pane.a2ui.json +6 -0
- package/components/pane/pane.class.js +3 -3
- package/components/pane/pane.css +3 -3
- package/components/pane/pane.yaml +3 -0
- package/components/password-strength/password-strength.a2ui.json +1 -0
- package/components/pipeline-status/pipeline-status.a2ui.json +1 -0
- package/components/popover/popover.a2ui.json +7 -6
- package/components/popover/popover.class.js +2 -2
- package/components/popover/popover.d.ts +2 -2
- package/components/popover/popover.yaml +4 -4
- package/components/preview/preview.a2ui.json +1 -0
- package/components/preview/preview.class.js +5 -1
- package/components/progress/progress.a2ui.json +47 -24
- package/components/progress/progress.class.js +66 -11
- package/components/progress/progress.css +44 -26
- package/components/progress/progress.d.ts +7 -5
- package/components/progress/progress.examples.md +2 -2
- package/components/progress/progress.yaml +235 -53
- package/components/progress-row/progress-row.a2ui.json +16 -12
- package/components/progress-row/progress-row.css +2 -2
- package/components/progress-row/progress-row.d.ts +2 -2
- package/components/progress-row/progress-row.examples.md +2 -14
- package/components/progress-row/progress-row.yaml +28 -36
- package/components/qr-code/qr-code.a2ui.json +13 -12
- package/components/qr-code/qr-code.class.js +7 -7
- package/components/qr-code/qr-code.css +1 -1
- package/components/qr-code/qr-code.d.ts +10 -7
- package/components/qr-code/qr-code.yaml +18 -12
- package/components/radio/radio.a2ui.json +8 -7
- package/components/radio/radio.class.js +8 -0
- package/components/radio/radio.yaml +3 -3
- package/components/radio-group/radio-group.a2ui.json +5 -3
- package/components/radio-group/radio-group.class.js +11 -0
- package/components/radio-group/radio-group.yaml +7 -1
- package/components/range/range.a2ui.json +6 -0
- package/components/range/range.class.js +2 -2
- package/components/range/range.css +3 -3
- package/components/range/range.yaml +3 -0
- package/components/rating/rating.a2ui.json +1 -0
- package/components/rating/rating.css +1 -1
- package/components/relative-time/relative-time.a2ui.json +1 -0
- package/components/richtext/richtext.a2ui.json +2 -1
- package/components/richtext/richtext.css +3 -3
- package/components/richtext/richtext.yaml +1 -1
- package/components/row/row.a2ui.json +1 -0
- package/components/search/search.a2ui.json +1 -0
- package/components/search/search.class.js +4 -1
- package/components/section/section.a2ui.json +1 -0
- package/components/segment/segment.a2ui.json +21 -10
- package/components/segment/segment.css +20 -4
- package/components/segment/segment.d.ts +2 -1
- package/components/segment/segment.yaml +20 -13
- package/components/segmented/segmented.a2ui.json +36 -7
- package/components/segmented/segmented.class.js +113 -22
- package/components/segmented/segmented.css +3 -0
- package/components/segmented/segmented.d.ts +3 -1
- package/components/segmented/segmented.yaml +80 -8
- package/components/select/select.a2ui.json +18 -13
- package/components/select/select.class.js +61 -37
- package/components/select/select.css +18 -16
- package/components/select/select.yaml +18 -7
- package/components/skeleton/skeleton.a2ui.json +8 -7
- package/components/skeleton/skeleton.class.js +8 -7
- package/components/skeleton/skeleton.css +21 -6
- package/components/skeleton/skeleton.d.ts +2 -2
- package/components/skeleton/skeleton.examples.md +2 -2
- package/components/skeleton/skeleton.yaml +3 -2
- package/components/skip-nav/skip-nav.a2ui.json +1 -0
- package/components/slider/slider.a2ui.json +6 -0
- package/components/slider/slider.class.js +20 -3
- package/components/slider/slider.css +2 -2
- package/components/slider/slider.yaml +3 -0
- package/components/spinner/spinner.a2ui.json +1 -0
- package/components/spinner/spinner.css +1 -1
- package/components/stack/stack.a2ui.json +1 -0
- package/components/stat/stat.a2ui.json +1 -0
- package/components/stat/stat.css +3 -3
- package/components/stat/stat.js +2 -2
- package/components/step-progress/step-progress.a2ui.json +1 -0
- package/components/step-progress/step-progress.css +1 -1
- package/components/step-progress/step-progress.yaml +1 -1
- package/components/stepper/stepper-item.a2ui.json +7 -3
- package/components/stepper/stepper-item.yaml +15 -5
- package/components/stepper/stepper.a2ui.json +5 -1
- package/components/stepper/stepper.class.js +31 -16
- package/components/stepper/stepper.css +2 -2
- package/components/stepper/stepper.d.ts +1 -1
- package/components/stepper/stepper.yaml +4 -2
- package/components/stream/stream.a2ui.json +1 -0
- package/components/swatch/swatch.a2ui.json +1 -0
- package/components/swatch/swatch.css +2 -2
- package/components/swiper/swiper.a2ui.json +1 -0
- package/components/swiper/swiper.class.js +5 -1
- package/components/switch/switch.a2ui.json +12 -11
- package/components/switch/switch.css +1 -1
- package/components/switch/switch.yaml +6 -6
- package/components/table/table.a2ui.json +1 -10
- package/components/table/table.class.js +18 -16
- package/components/table/table.css +17 -18
- package/components/table/table.d.ts +0 -2
- package/components/table/table.yaml +0 -9
- package/components/table-toolbar/table-toolbar.a2ui.json +1 -0
- package/components/table-toolbar/table-toolbar.class.js +38 -19
- package/components/table-toolbar/table-toolbar.css +2 -2
- package/components/tabs/tab.a2ui.json +9 -0
- package/components/tabs/tab.js +4 -0
- package/components/tabs/tab.yaml +15 -0
- package/components/tabs/tabs.a2ui.json +9 -4
- package/components/tabs/tabs.class.js +13 -1
- package/components/tabs/tabs.css +9 -1
- package/components/tabs/tabs.d.ts +2 -0
- package/components/tabs/tabs.yaml +9 -2
- package/components/tag/tag.a2ui.json +1 -0
- package/components/tag/tag.css +2 -2
- package/components/tags-input/tags-input.a2ui.json +22 -17
- package/components/tags-input/tags-input.class.js +13 -11
- package/components/tags-input/tags-input.css +11 -7
- package/components/tags-input/tags-input.d.ts +16 -7
- package/components/tags-input/tags-input.examples.md +2 -2
- package/components/tags-input/tags-input.yaml +25 -8
- package/components/text/text.a2ui.json +6 -5
- package/components/text/text.css +10 -5
- package/components/text/text.d.ts +2 -2
- package/components/text/text.yaml +9 -4
- package/components/textarea/textarea.a2ui.json +2 -1
- package/components/textarea/textarea.css +1 -1
- package/components/textarea/textarea.yaml +1 -1
- package/components/theme-provider/theme-provider.a2ui.json +2 -1
- package/components/theme-provider/theme-provider.d.ts +5 -3
- package/components/theme-provider/theme-provider.yaml +5 -3
- package/components/time-picker/time-picker.a2ui.json +1 -0
- package/components/time-picker/time-picker.class.js +4 -2
- package/components/time-picker/time-picker.css +1 -1
- package/components/timeline/timeline-item.a2ui.json +26 -3
- package/components/timeline/timeline-item.yaml +22 -7
- package/components/timeline/timeline.a2ui.json +4 -0
- package/components/timeline/timeline.class.js +29 -18
- package/components/timeline/timeline.css +4 -4
- package/components/timeline/timeline.d.ts +3 -3
- package/components/timeline/timeline.yaml +2 -0
- package/components/toast/toast.a2ui.json +10 -3
- package/components/toast/toast.yaml +20 -13
- package/components/toc/toc.a2ui.json +1 -0
- package/components/toc/toc.css +1 -1
- package/components/toggle-group/toggle-group.a2ui.json +7 -3
- package/components/toggle-group/toggle-group.class.js +43 -12
- package/components/toggle-group/toggle-group.css +7 -4
- package/components/toggle-group/toggle-group.d.ts +3 -4
- package/components/toggle-group/toggle-group.yaml +22 -16
- package/components/toggle-group/toggle-option.a2ui.json +8 -4
- package/components/toggle-group/toggle-option.yaml +15 -13
- package/components/toggle-scheme/toggle-scheme.a2ui.json +2 -1
- package/components/toggle-scheme/toggle-scheme.yaml +1 -1
- package/components/toolbar/toolbar-group.a2ui.json +1 -0
- package/components/toolbar/toolbar.a2ui.json +1 -0
- package/components/toolbar/toolbar.class.js +3 -0
- package/components/tooltip/tooltip.a2ui.json +1 -0
- package/components/tooltip/tooltip.css +1 -1
- package/components/tour/tour-step.a2ui.json +4 -0
- package/components/tour/tour-step.yaml +2 -0
- package/components/tour/tour.a2ui.json +4 -0
- package/components/tour/tour.css +2 -2
- package/components/tour/tour.yaml +2 -0
- package/components/tree/tree-item.a2ui.json +5 -0
- package/components/tree/tree-item.yaml +3 -0
- package/components/tree/tree.a2ui.json +4 -0
- package/components/tree/tree.class.js +2 -1
- package/components/tree/tree.css +1 -1
- package/components/tree/tree.yaml +2 -0
- package/components/upload/upload.a2ui.json +8 -1
- package/components/upload/upload.class.js +35 -5
- package/components/upload/upload.css +28 -0
- package/components/upload/upload.d.ts +16 -0
- package/components/upload/upload.yaml +27 -7
- package/components/visually-hidden/visually-hidden.a2ui.json +1 -0
- package/core/dom.d.ts +11 -0
- package/core/dom.js +34 -0
- package/core/form.js +7 -0
- package/core/index.d.ts +1 -0
- package/core/index.js +1 -0
- package/core/responsive.js +16 -4
- package/core/template.js +2 -1
- package/custom-elements.json +442 -502
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +5 -5
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +91 -104
- package/dist/web-components.sheet.js +1 -1
- package/package.json +4 -2
- package/patterns/conversion-funnel/conversion-funnel.examples.html +15 -15
- package/patterns/inline-dialog/inline-dialog.examples.html +2 -2
- package/patterns/inline-dialog/inline-dialog.html +4 -0
- package/patterns/timezone-selector/timezone-selector.examples.html +1 -1
- package/patterns/timezone-selector/timezone-selector.html +2 -2
- package/styles/api/text.css +7 -0
- package/styles/type/scale.css +6 -7
- package/traits/_catalog.json +129 -41
- package/traits/anchor-positioning/anchor-positioning.js +1 -0
- package/traits/announcer/announcer.js +1 -0
- package/traits/arrow-grid-nav/arrow-grid-nav.js +1 -0
- package/traits/attention-pulse/attention-pulse.js +1 -0
- package/traits/count-up/count-up.js +1 -0
- package/traits/define.js +78 -0
- package/traits/focus-restore/focus-restore.js +2 -1
- package/traits/haptic-feedback/haptic-feedback.js +1 -0
- package/traits/input-mask/input-mask.js +1 -0
- package/traits/intersection-observer/intersection-observer.js +1 -0
- package/traits/layout-animation/layout-animation.js +1 -0
- package/traits/noise-texture/noise-texture.js +1 -0
- package/traits/resize-observer/resize-observer.js +1 -0
- package/traits/scroll-progress/scroll-progress.js +1 -0
- package/traits/snap-to-grid/snap-to-grid.js +1 -0
- package/traits/sound-feedback/sound-feedback.js +1 -0
- package/traits/spring-animate/spring-animate.js +1 -0
- package/traits/validation/validation.js +1 -0
package/MIGRATION.md
CHANGED
|
@@ -41,7 +41,7 @@ Version cuts and migration scope:
|
|
|
41
41
|
- **Recommended consumer migration:** if you were using `@adia-ai/web-modules/runtime/a2ui-root/a2ui-root.js` + `@adia-ai/web-components/components/canvas/canvas.js` for generative UI surfaces, collapse to a single `import '@adia-ai/web-modules/generative'`. Both old paths still work.
|
|
42
42
|
- See [§ v0.6.7 section below](#migrating-to-adia-aiv067-2026-05-19).
|
|
43
43
|
|
|
44
|
-
- **
|
|
44
|
+
- **Shipped in `0.8.33` (variant/color/tone convention cut, ADR-0044)** — **BREAKING:** `accent` is retired as an enum value on `badge-ui` (`variant`), `tag-ui` (`variant`), and `button-ui` (`color`) — `primary` is the brand-emphasis value on badge/tag (identical rendering; pure rename). Badge-ui's `variant` becomes family-only: `variant="muted"` / `variant="neutral"` are removed — both map to `tone="muted"` (the fill-style axis they always belonged on). Badge's family-less `tone="muted"` also re-tokens to the `--md-sys-color-neutral-low` fill (a visibly stronger tint — no markup change). The same one-axis rule then reaches **alert-ui** (`variant="muted"` / `"neutral"` removed — they were exact aliases of the default, so just drop the attribute; zero visual change) and **mark-ui** (`variant="muted"` removed with no enum successor — a neutral highlight is now a `--mark-bg`/`--mark-fg` token override); neither gains a `tone` axis. `accent` on OTHER components (icon-ui, text-ui, chart-ui, …) is unchanged. See [§ Shipped in `0.8.33` — variant/color/tone convention cut](#upcoming-variant-color-tone-convention-cut).
|
|
45
45
|
|
|
46
46
|
- **Upcoming (`<theme-provider>` cut)** — **BREAKING:** the token-theme attribute is renamed `data-theme` → `theme` repo-wide. Replace `<html data-theme="ocean">` → `<html theme="ocean">` and any `[data-theme="…"]` selectors → `[theme="…"]`. Mechanical: a word-boundary find-replace of `data-theme` → `theme` (preserve compound attrs like `data-theme-slug` / `data-themed`). Pre-1.0 PATCH cadence. Also new: the **`<theme-provider>`** element adopts the AdiaUI foundation into the document from anywhere (no `<head>` stylesheet link), with opt-in `theme="…"` (named preset) + `scale="verse|prose"` (typographic register) attributes that fetch their layer on demand.
|
|
47
47
|
- **`theme` ≠ `scheme` — don't conflate the two axes.** This rename is purely the *theme* axis (a named preset: ocean / forest / slate / …). A light/dark *mode* is the orthogonal *scheme* axis — it belongs on `color-scheme` / `data-scheme`, **never** on `[theme]`. If you'd encoded a mode as `data-theme="dark"`, that was a category error: after the rename it is a no-op on *both* axes. Move it to the scheme axis — `<html style="color-scheme: dark">`, `data-scheme`, or `<toggle-scheme-ui>`. (Surfaced by color-app, 2026-06-07.)
|
|
@@ -54,6 +54,34 @@ Version cuts and migration scope:
|
|
|
54
54
|
|
|
55
55
|
- **`0.8.37`** — PATCH lockstep cut. **BREAKING: the a2ui / gen-ui estate split (ADR-0048).** Six published package names (`a2ui-runtime`, `a2ui-compose`, `a2ui-corpus`, `a2ui-retrieval`, `a2ui-validator`, `a2ui-mcp`) are replaced by four (`a2ui`, `gen-ui`, `gen-ui-mcp`, `a2ui-protocol-mcp`). **A patch-shaped version number does not make this non-breaking** — every old name is renamed. One-cycle re-export shims bridge the gap; the cut AFTER `0.8.37` retires them. See [§ 0.8.37 — the a2ui / gen-ui estate split](#0837--the-a2ui--gen-ui-estate-split-adr-0048).
|
|
56
56
|
|
|
57
|
+
- **Shipped in `0.8.40` (attribute-grammar reconciliation, ADR-0054)** — **BREAKING, no deprecation alias:** `table-ui[density]` converges onto the ambient global `[density]` attribute — the component-local `compact`/`standard`/`comfortable` enum is removed. Migration: `density="compact"` stays `density="compact"`; `density="standard"` → drop the attribute (unset is the default); `density="comfortable"` → `density="spacious"`. `chart-ui[radius]` renames to `chart-ui[corner-radius]` (same `Number`/`null` semantics, same `--a-radius` fallback) — a mechanical attribute-name rename, no value-shape change. `swatch-ui[color]` and `noodles-ui[color]` are ratified exceptions and are unaffected. See [§ Shipped in `0.8.40` — attribute-grammar reconciliation](#upcoming-0840-attribute-grammar-reconciliation-adr-0054).
|
|
58
|
+
|
|
59
|
+
- **Shipped in `0.8.40` (`qr-code-ui` quiet-zone rename)** — **BREAKING:** `<qr-code-ui>`'s reflected `[margin]` attribute is renamed `[quiet-zone]` (property `quietZone`) — same type, default (`4`), and reflection; only the name changes, per [ADR-0053](../../docs/ops/adr/adr-0053-no-shadowing-global-attributes.md). `margin` on `qr-code-ui` now means the framework's **global** `[margin]` Scale attribute (box-model spacing), not the QR quiet zone — the two grammars silently collided on the same syntax with unrelated meanings. **No deprecation alias** — keeping `margin` as an alias would preserve the collision the rename exists to remove. Audit existing usages: `<qr-code-ui margin="4">` intending a quiet zone must become `<qr-code-ui quiet-zone="4">`. Shipped in `0.8.40`. See [§ Shipped in `0.8.40` — qr-code-ui quiet-zone rename](#upcoming--qr-code-ui-quiet-zone-rename-adr-0053).
|
|
60
|
+
|
|
61
|
+
- **Shipped in `0.8.40` (leading-scale consolidation)** — **BREAKING, no aliases:** the legacy `--a-leading-*` token family is removed per [ADR-0052](../../docs/ops/adr/adr-0052-leading-scale-consolidation.md) — `--a-font-leading-*` (+ new `--a-font-leading-none: 1` step) is now the single canonical leading scale. Value-nearest replacement table: `none→--a-font-leading-none` (1), `tight→--a-font-leading-snug` (1.2), `snug→--a-font-leading-normal` (1.35), `normal→--a-font-leading-relaxed` (1.5). The same gh#1298 sweep also tokenized every hardcoded `line-height`/`letter-spacing`/`font-weight` literal across `packages/web-components/components/*/*.css` (1.3 and 1.4 both → `--a-font-leading-normal`; 0.05em → `--a-font-tracking-wide`) and added a mechanized `npm run check:typography-tokens` gate. See [§ Shipped in `0.8.40` — leading-scale consolidation](#upcoming--leading-scale-consolidation-adr-0052).
|
|
62
|
+
|
|
63
|
+
- **Shipped in `0.8.40` (`toggle-option-ui` drops `data-selected`)** — **BREAKING, no deprecation alias:** `<toggle-group-ui>`'s legacy `data-selected` parallel stamp on its `<toggle-option-ui>` children is removed per [ADR-0056](../../docs/ops/adr/adr-0056-selection-item-selected-convention.md) — the declared, reflected `selected` prop (shipped additively in `0.8.39`) is now the only current-state surface, matching `<segment-ui>`'s convention. Migration: any `[data-selected]` CSS or script targeting `toggle-option-ui` moves to `[selected]`. See [§ Shipped in `0.8.40` — `toggle-option-ui` drops the legacy `data-selected` stamp](#upcoming--toggle-option-ui-drops-the-legacy-data-selected-stamp-0840-adr-0056).
|
|
64
|
+
|
|
65
|
+
- **Shipped in `0.8.41` (`progress-ui` retires `variant`, gh#1370)** — **BREAKING, no deprecation alias:** `<progress-ui>`'s `variant` prop (`bar` | `spinner`) is removed — progress is bar-only now. The former `variant="spinner"` render mode (a Sanctioned Mode Attribute per the component-token-contract) is gone; `<spinner-ui>` owns circular loading indicators (`arc`/`ring`/`dots`/`knight`). Migration: `<progress-ui variant="spinner">` → `<spinner-ui>` (pick the closest `variant`; `arc` is the nearest visual match to the old spinner render). `<progress-ui variant="bar">` → drop the attribute (bar was already the default). Filed from the catalog-regularity audit's C2 finding (gh#1363) — a 2026-06 merge folded a standalone spinner into progress as `variant="spinner"`, then a richer standalone `spinner-ui` was re-added later, leaving two circular-loading answers in the catalog; this rider un-forks them. See [§ Shipped in `0.8.41` — `progress-ui` retires `variant`](#upcoming--progress-ui-retires-variant-090-gh1370).
|
|
66
|
+
|
|
67
|
+
- **Shipped in `0.8.41` (`input-ui` trims `type` enum, gh#1381)** — **BREAKING, no deprecation alias:** `<input-ui>`'s `type` enum drops `search`/`date`/`datetime-local`/`time`/`month`/`week`/`color` — none ever rendered a native affordance (all seven fell back to a plain contenteditable surface), so the enum was first-pass-VALID but functionally broken generation output. The implemented set is now exactly `text`/`email`/`password`/`number`/`tel`/`url`. Migration: `type="search"` → `<search-ui>`; `type="date"`/`"month"`/`"week"` → `<calendar-picker-ui>` (day granularity only — no dedicated month/week primitive exists); `type="datetime-local"` → `<datetime-picker-ui>`; `type="time"` → `<time-picker-ui>`; `type="color"` → `<color-input-ui>` (or `<color-picker-ui>` directly for a full-surface editor). Filed from the catalog-regularity audit's B10 finding (gh#1363). See [§ Shipped in `0.8.41` — `input-ui` trims `type` enum](#upcoming--input-ui-trims-type-enum-090-gh1381).
|
|
68
|
+
|
|
69
|
+
- **Shipped in `0.8.41` (web-modules `data-*` state converges to bare attributes, gh#1332)** — **BREAKING, no deprecation alias:** two web-modules' declared `states:` entries drop a private `data-*` stamp for a bare state attribute, per the data-* usage sweep's Category A disposition (ADR-0056's rule generalized past `toggle-option-ui`). `<integrations-page-ui>`'s `empty-search`/`empty-data` states (was `data-empty-search`/`data-empty-data`) and `<onboarding-checklist-ui>`'s `complete` state (was `data-complete`) now match their own sibling states' existing bare-attribute convention (`loading`, `collapsed`). Migration: any `[data-empty-search]`/`[data-empty-data]`/`[data-complete]` CSS or script targeting these two modules moves to `[empty-search]`/`[empty-data]`/`[complete]`. See [§ Shipped in `0.8.41` — web-modules data-* state converges to bare attributes](#upcoming--web-modules-data--state-converges-to-bare-attributes-090-gh1332).
|
|
70
|
+
|
|
71
|
+
- **Shipped in `0.8.41` (`action-item-ui` converges onto `menu-item-ui`'s row contract, gh#1374)** — **BREAKING, no deprecation alias, zero known consumer sites.** `<action-item-ui>` gains a `subtitle` prop + `text`/`subtitle`/`trailing` slot overrides, matching `<menu-item-ui>`'s row contract exactly. The unnamed default slot this row previously used for trailing content (kbd shortcut, badge, caret) is retired in favor of an explicit `slot="trailing"` — a monorepo-wide sweep at dispatch time found no consumer relying on it (every `<action-item-ui>` usage is self-closing/attribute-only). Migration: any external consumer slotting unnamed trailing content into `<action-item-ui>` adds `slot="trailing"` to that child. Filed from the catalog-regularity audit's C5 finding (gh#1363) — action-list's container-level "should this become a `list-ui` mode" question was decided as NO (kept as a separate component; see the ticket's Findings for rationale), leaving only this row-level convergence to ship. See [§ Shipped in `0.8.41` — `action-item-ui` converges onto `menu-item-ui`'s row contract](#upcoming--action-item-ui-converges-onto-menu-item-uis-row-contract-090-gh1374).
|
|
72
|
+
|
|
73
|
+
- **Shipped in `0.8.41` (global-attribute-shadowing collision sweep, gh#1335)** — **BREAKING, no deprecation aliases:** of the 16 pre-existing component-local attributes that shadowed the global attribute grammar (surfaced by the `check:attribute-shadowing` gate, ADR-0053/0054's own decision-4 gate), 14 are resolved here — 11 renamed/converged, 3 exempted (an ADR-ratified §11 pass-through, no code change) — plus a 17th collision this same ticket's own follow-up audit surfaced (`dashboard-layout-ui[gap]`, never in the gate's original 16 since its shape wasn't caught by the gate's type-only check), also renamed here, for **12 renames/conversions + 3 exemptions = 15 items resolved of 17 tracked**: `header-ui[padding]` → `[padded]`; `menu-ui`/`popover-ui[gap]` → `[offset]`; `skeleton-ui`/`image-ui[radius]` → `[corner-radius]`; `invoice-detail-ui`/`invoice-history-ui`/`dashboard-layout-ui[density]` converge onto `compact`/`spacious`/unset; `dashboard-layout-ui[gap]` → `[band-gap]`; `text-ui[weight]` `regular` → `normal`; `text-ui[text-align]` converges onto the global physical vocabulary (`start`/`end` → `left`/`right`; `justify` newly supported by the global `[text-align]` grammar too); `tags-input-ui[transform]` → `[normalize]`; `button-ui`/`toggle-scheme-ui`/`text-ui[color]` are newly §11-ratified exemptions (ADR-0044/ADR-0064 — these play the FAMILY axis, a different grammar from the generic descriptive `[color]`, not a foreign-value violation). `qr-code-ui[color]` and `icon-ui[weight]` were left open by this sweep (both genuine §11-exemption candidates with no ratifying ADR at the time, tracked in the gate's own `KNOWN_FINDINGS`) and are since ratified as §11 exemptions by ADR-0070 (gh#1500) — no code change, closing the ledger at 17 of 17. See [§ Shipped in `0.8.41` — global-attribute-shadowing collision sweep](#upcoming--global-attribute-shadowing-collision-sweep-090-gh1335).
|
|
74
|
+
|
|
75
|
+
- **Shipped in `0.8.41` (A2UI catalog `component:` collision — `AdminShell` / `UIChatThread`, gh#1427)** — **BREAKING for hand-authored/generated A2UI documents only — no DOM/JS API or tag-name change.** `admin-shell.yaml` and `embed-shell.yaml` both declared catalog identity `component: AppShell`, so alphabetical build traversal silently dropped `admin-shell`'s L0 catalog entry (embed-shell's fragment won). Fixed: `admin-shell`'s catalog identity is now `AdminShell` (its own established `registry.js` mapping); `embed-shell` keeps `AppShell`. The same build-time collision guard added to catch this also caught `chat-thread-ui`'s primitive yaml still declaring `component: ChatThread`, colliding with the chat web-module's own `ChatThread` — the primitive's catalog identity is now `UIChatThread`. A raw a2ui tree with `{"component": "AppShell"}` meaning the stable admin shell, or `{"component": "ChatThread"}` meaning the standalone primitive, needs updating; the HTML tags (`<admin-shell>`, `<chat-thread-ui>`) are unaffected. See [§ Shipped in `0.8.41` — A2UI catalog `component:` collision](#upcoming--a2ui-catalog-component-collision-adminshell--uichatthread-090-gh1427).
|
|
76
|
+
|
|
77
|
+
- **Shipped in `0.8.41` (`progress-row-ui` deprecated — absorbed into `progress-ui`, gh#1373)** — **Non-breaking, deprecation alias.** `<progress-ui>` gains `label` + `meta` props; a non-empty `label` activates the identical labeled-row layout `<progress-row-ui>` used to own (a new Sanctioned Mode Attribute per the component-token-contract). `<progress-row-ui>` keeps working unchanged (still composes `<progress-ui>` internally) but ships `status: deprecated` and is no longer taught to the A2UI catalog or generated for new work. Migration: `<progress-row-ui label="…" value="…" meta="…">` → `<progress-ui label="…" value="…" meta="…">` — attribute names are identical, a mechanical tag rename. `variant` (the color-family prop on the old component) has **no successor on `<progress-ui>`** — progress's `variant` prop was already retired bar-only in the gh#1370 C2 rider and stayed retired; recolor the fill via the `--progress-fill` token instead (`--progress-fill: var(--a-success-bg)` etc.), consistent with progress's existing token-only convention. Filed from the catalog-regularity audit's C4 finding (gh#1363) — progress's own canonical catalog example already put `label` on a `Progress` node, meaning generation copying that exemplar failed validation before this rider. See [§ Shipped in `0.8.41` — `progress-row-ui` deprecated](#upcoming--progress-row-ui-deprecated--absorbed-into-progress-ui-090-gh1373).
|
|
78
|
+
- **Shipped in `0.8.41` (`segmented-ui` gains `[multiple]`; `toggle-group-ui`/`toggle-option-ui` deprecated, gh#1369)** — **Additive, non-breaking + soft deprecation (no removal).** `<segmented-ui>` gains a `multiple: Boolean` axis (default `false`, positive polarity matching `select-ui[multiple]`): under `[multiple]`, `value` is a comma-separated set (same encoding `toggle-group-ui` and `select-ui[multiple]` already use), the sliding indicator is suppressed, each selected `<segment-ui>` carries its own background instead, and Space/Enter toggles a focused segment rather than arrow-move selecting it. `<toggle-group-ui>` + `<toggle-option-ui>` are marked `status: deprecated` and log a one-time `console.warn` — they keep working exactly as before, no behavior change. **Recommended migration:** `<toggle-group-ui value="…">` + `<toggle-option-ui>` children → `<segmented-ui multiple value="…">` + `<segment-ui>` children (value encoding is identical; `text`/`icon`/`disabled` map directly). Filed from the catalog-regularity audit's C1 finding (gh#1363) — the strongest-ranked consolidation candidate: `toggle-group-ui` already had a `single` mode prop making it segmented, and had zero corpus chunks vs. segmented/segment's 19 each, so multi-select intents retrieved nothing or mis-retrieved single-select chunks. See [§ Shipped in `0.8.41` — `segmented-ui` gains `[multiple]`](#upcoming--segmented-ui-gains-multiple-toggle-group-uitoggle-option-ui-deprecated-090-gh1369).
|
|
79
|
+
|
|
80
|
+
- **Shipped in `0.8.41` (`calendar-picker-ui` absorbs `datetime-picker-ui`, gh#1372)** — **Mostly additive + soft deprecation; two real breaking removals on `calendar-picker-ui` itself.** `<calendar-picker-ui>` gains a `precision` axis (`date`|`minute`|`second`, default `date` — unchanged for every existing consumer) plus `step`/`hour-cycle`/`locale` and the `input`/`open`/`close`/`invalid` events datetime mode needs. `<datetime-picker-ui>` is now `status: deprecated`, implemented as a thin `calendar-picker-ui` subclass (`precision="minute"` by default) — it keeps working unchanged; **recommended (non-breaking) migration:** `<datetime-picker-ui>` → `<calendar-picker-ui precision="minute">`. **Breaking, no deprecation alias:** `<calendar-picker-ui>`'s own `label` prop/slot are removed — wrap in `<field-ui label>` instead, matching every sibling picker (this was `calendar-picker-ui`'s own outlier); and `<datetime-picker-ui>`'s `--datetime-picker-*` CSS tokens are removed — styling now flows through `<calendar-picker-ui>`'s shared `--calendar-picker-*` tokens. Filed from the catalog-regularity audit's C3c/C3d findings (gh#1363). See [§ Shipped in `0.8.41` — `calendar-picker-ui` absorbs `datetime-picker-ui`](#upcoming--calendar-picker-ui-absorbs-datetime-picker-ui-behind-a-widened-precision-axis-090-gh1372).
|
|
81
|
+
- **Shipped in `0.8.41` (primitive-tier `data-*` state converges to bare attributes, gh#1332)** — **BREAKING, no deprecation alias.** The residual primitive-tier round of the [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332) (Category A), following the web-modules round above: `<feed-item-ui>`'s `[data-open]`/`[data-closing]` states and its `[data-queued]` max-queue marker (stamped by the parent `<feed-ui>`'s post logic, carried on the item) converge to bare `[open]`/`[closing]`/`[queued]`; `<slider-ui>` and `<range-ui>`'s `[data-dragging]` converges to bare `[dragging]`; `<pane-ui>`'s `[data-resizing]` converges to bare `[resizing]` (matching admin-sidebar/chat-sidebar's own `[resizing]` convention from the web-modules round); `<chart-ui>`'s `[data-has-data]` converges to bare `[has-data]`; `<select-ui>`'s private `[data-multi-chips]` mirror is dropped outright — its 8 CSS selectors now key off the compound `[multiple]:not([summary-label])`, both already-declared reflected props, no bare successor attribute needed. See [§ Shipped in `0.8.41` — primitive-tier data-* state converges to bare attributes](#upcoming--primitive-tier-data--state-converges-to-bare-attributes-090-gh1332-2).
|
|
82
|
+
|
|
83
|
+
- **Shipped in `0.8.41` (`image-ui` load/error states declared + converge to bare attributes, gh#1464)** — **BREAKING, no deprecation alias.** The final residue of the [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332), deferred out of the residual round above because it needed a new `states:` declaration rather than a bare mapping change: `<image-ui>`'s `[data-loaded]`/`[data-error]` were genuine undeclared host-level state (never yaml-declared at all) — now declared as `loaded`/`error` in `image.yaml`'s `states:` list with bare `attribute:` mappings, matching qr-code-ui's own converged `error` state. Migration: any `[data-loaded]`/`[data-error]` CSS or script targeting `image-ui` moves to `[loaded]`/`[error]`; `image-ui`'s unrelated `[data-overlay]` skeleton-proximity marker (gh#1362) is untouched. A repo-wide consumer sweep (`rg -nU 'data-loaded|data-error'`) found zero external consumers of image-ui's forms specifically, so no deprecation alias was kept. The same ticket also dispositioned the `data-msg-*` validation-message config family (`data-msg-required`/`pattern`/`minlength`/`maxlength`/`min`/`max`/`bad-input`) as **exempt, non-breaking, no migration** — it stays `data-*` by design (component-side config read by `core/form.js`'s shared mixin across 7+ components, not host-reflected state; see `primitive-authoring/references/yaml-contract.md`'s new `data-msg-*` section for the full rationale). See [§ Shipped in `0.8.41` — image-ui load/error states declared + converge to bare attributes](#upcoming--image-ui-loaderror-states-declared--converge-to-bare-attributes-090-gh1464).
|
|
84
|
+
|
|
57
85
|
Live demos and per-component docs at [ui-kit.exe.xyz/site/](https://ui-kit.exe.xyz/site/). The `adia-ui-migration` skill (in `.agents/skills/`) automates most of the mechanical sweeps in this guide.
|
|
58
86
|
|
|
59
87
|
---
|
|
@@ -65,7 +93,7 @@ cut renames six published packages. Nothing about the rename is patch-shaped
|
|
|
65
93
|
except the number, which is an operator ruling (gh#1192, 2026-08-13) about
|
|
66
94
|
release cadence, not a claim that your imports keep working forever.
|
|
67
95
|
|
|
68
|
-
The split is by concept, ruled in `docs/adr/adr-0048-a2ui-gen-ui-estate-split.md`:
|
|
96
|
+
The split is by concept, ruled in `docs/ops/adr/adr-0048-a2ui-gen-ui-estate-split.md`:
|
|
69
97
|
|
|
70
98
|
- **`@adia-ai/a2ui` — the protocol.** How one system renders gen-UI canvases
|
|
71
99
|
in another system, safely: renderer, registry, streams, surface, wiring,
|
|
@@ -242,7 +270,8 @@ between a dependency and a peer:
|
|
|
242
270
|
|
|
243
271
|
---
|
|
244
272
|
|
|
245
|
-
|
|
273
|
+
<a id="upcoming-variant-color-tone-convention-cut"></a>
|
|
274
|
+
## Shipped in `0.8.33` — variant/color/tone convention cut (ADR-0044, gh#873/874/875/876/881)
|
|
246
275
|
|
|
247
276
|
**One theme: every color-ish attribute owns exactly one axis.** `variant`/`tone` on badge & tag
|
|
248
277
|
and `variant`/`color` on button now each carry either a *semantic family* or a *fill style*,
|
|
@@ -384,6 +413,1243 @@ npm run check # in-repo consumers; downstream: your app's build + a visual pas
|
|
|
384
413
|
|
|
385
414
|
---
|
|
386
415
|
|
|
416
|
+
<a id="upcoming-0840-attribute-grammar-reconciliation-adr-0054"></a>
|
|
417
|
+
## Shipped in `0.8.40` — attribute-grammar reconciliation (ADR-0054)
|
|
418
|
+
|
|
419
|
+
**BREAKING, no deprecation alias.** [ADR-0054](../../docs/ops/adr/adr-0054-attribute-grammar-reconciliation.md)
|
|
420
|
+
resolves two component-local attributes that shadowed the [global attribute
|
|
421
|
+
grammar](../../.claude/docs/specs/attribute-api-system.md) with divergent vocabularies —
|
|
422
|
+
`table-ui[density]` **converges** onto the global mechanism (it already did
|
|
423
|
+
the job), `chart-ui[radius]` **renames** (a numeric px value is a genuinely
|
|
424
|
+
different shape than the global preset enum). Per [ADR-0053](../../docs/ops/adr/adr-0053-no-shadowing-global-attributes.md),
|
|
425
|
+
neither collision is exempted — `swatch-ui[color]` / `noodles-ui[color]` are
|
|
426
|
+
the only two ratified exceptions (documented in
|
|
427
|
+
[§11 of attribute-api-system.md](../../.claude/docs/specs/attribute-api-system.md#11-global-attribute-exemption-list)),
|
|
428
|
+
and neither is touched by this cut.
|
|
429
|
+
|
|
430
|
+
### `table-ui[density]` converges onto the global grammar
|
|
431
|
+
|
|
432
|
+
The component-local `compact | standard | comfortable` enum is removed —
|
|
433
|
+
`table-ui` no longer reflects a `density` prop or JS property at all.
|
|
434
|
+
`[density]` on `table-ui` is now the ordinary ambient global attribute
|
|
435
|
+
(`compact | spacious`, unset = the middle) — `--table-py`/`--table-px`
|
|
436
|
+
already derive from `--a-space-*` steps, which the global `[density]`
|
|
437
|
+
attribute already scales via `--a-density`.
|
|
438
|
+
|
|
439
|
+
**Value migration** (apply wherever `<table-ui density="…">` appears):
|
|
440
|
+
|
|
441
|
+
| Old value | New value |
|
|
442
|
+
|---|---|
|
|
443
|
+
| `density="compact"` | `density="compact"` (unchanged) |
|
|
444
|
+
| `density="standard"` | drop the attribute entirely (unset is the default) |
|
|
445
|
+
| `density="comfortable"` | `density="spacious"` |
|
|
446
|
+
|
|
447
|
+
```bash
|
|
448
|
+
# find every table-ui density usage in your tree
|
|
449
|
+
git grep -nE '<table-ui[^>]*\bdensity='
|
|
450
|
+
|
|
451
|
+
# comfortable → spacious (mechanical)
|
|
452
|
+
git grep -lz '<table-ui[^>]*density="comfortable"' | while IFS= read -r -d '' f; do
|
|
453
|
+
perl -i -pe 's/(<table-ui[^>]*density=")comfortable(")/${1}spacious${2}/g' "$f"
|
|
454
|
+
done
|
|
455
|
+
|
|
456
|
+
# standard → drop the attribute (review each hit; not always a safe blind sed
|
|
457
|
+
# across multi-line tags)
|
|
458
|
+
git grep -nE '<table-ui[^>]*density="standard"'
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
If you read/write a table's `density` as a JS property (`el.density`) or
|
|
462
|
+
persisted it via `table-ui`'s `getState()`/`setState()`, switch to
|
|
463
|
+
`getAttribute('density')`/`setAttribute('density', …)` — the reflected
|
|
464
|
+
property and the `getState()`/`setState()` `density` key are both gone.
|
|
465
|
+
Composites that forward density to an embedded `table-ui` (own component,
|
|
466
|
+
own vocabulary) must translate through the same table above before setting
|
|
467
|
+
the child's attribute — see `invoice-history.class.js`'s `mapDensity()` for
|
|
468
|
+
the pattern.
|
|
469
|
+
|
|
470
|
+
### `chart-ui[radius]` renames to `chart-ui[corner-radius]`
|
|
471
|
+
|
|
472
|
+
Same `Number` type, same `default: null` (falls back to `--a-radius`), same
|
|
473
|
+
behavior — only the attribute name changes.
|
|
474
|
+
|
|
475
|
+
```bash
|
|
476
|
+
git grep -nE '<chart-ui[^>]*\bradius='
|
|
477
|
+
git grep -lz '<chart-ui[^>]*radius="' | while IFS= read -r -d '' f; do
|
|
478
|
+
perl -i -pe 's/(<chart-ui[^>]*)\bradius=/${1}corner-radius=/g' "$f"
|
|
479
|
+
done
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
If you set it via JS, `chart.radius = 8` → `chart.cornerRadius = 8`.
|
|
483
|
+
|
|
484
|
+
### Verify
|
|
485
|
+
|
|
486
|
+
```bash
|
|
487
|
+
git grep -nE '<table-ui[^>]*\bdensity="(standard|comfortable)"' # must be 0
|
|
488
|
+
git grep -nE '<chart-ui[^>]*\bradius=' # must be 0
|
|
489
|
+
npm run check
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
<a id="upcoming--qr-code-ui-quiet-zone-rename-adr-0053"></a>
|
|
495
|
+
## Shipped in `0.8.40` — qr-code-ui quiet-zone rename (ADR-0053)
|
|
496
|
+
|
|
497
|
+
**BREAKING, ships in `0.8.40`.** `<qr-code-ui>`'s reflected `[margin]` attribute is
|
|
498
|
+
renamed `[quiet-zone]` (property `quietZone`) — same `number` type, same default (`4`), same
|
|
499
|
+
reflection; only the name changes.
|
|
500
|
+
|
|
501
|
+
**Why:** the framework's global attribute grammar (`styles/api/*.css`) is a pitch — one
|
|
502
|
+
grammar, inferable: `margin="4"` means the same thing on every element, resolving through one
|
|
503
|
+
Scale mechanism (`--a-margin`). `qr-code-ui` declared its own reflected `margin` meaning the QR
|
|
504
|
+
"quiet zone" in grid cells. Both grammars accepted the identical syntax with no error surfaced,
|
|
505
|
+
so an author reaching for `<qr-code-ui margin="4">` expecting global spacing silently got a
|
|
506
|
+
quiet-zone resize instead, and vice versa. [ADR-0053](../../docs/ops/adr/adr-0053-no-shadowing-global-attributes.md)
|
|
507
|
+
rules that no component-local attribute may shadow a global one; this is the first instance
|
|
508
|
+
resolved under that policy (gh#1299).
|
|
509
|
+
|
|
510
|
+
**No deprecation alias.** Keeping `margin` as an alias on `qr-code-ui` would preserve the exact
|
|
511
|
+
collision the rename exists to remove — `margin` on `qr-code-ui` reverts to meaning what it
|
|
512
|
+
means everywhere: the global Scale attribute.
|
|
513
|
+
|
|
514
|
+
### Mechanical sweep
|
|
515
|
+
|
|
516
|
+
```bash
|
|
517
|
+
git grep -nE '<qr-code-ui[^>]*\smargin='
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
Every hit intending the QR quiet zone becomes `quiet-zone`:
|
|
521
|
+
|
|
522
|
+
```html
|
|
523
|
+
<!-- before --> <qr-code-ui value="…" margin="4"></qr-code-ui>
|
|
524
|
+
<!-- after --> <qr-code-ui value="…" quiet-zone="4"></qr-code-ui>
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Programmatic setters** (JS render paths — the grep above misses these):
|
|
528
|
+
|
|
529
|
+
```bash
|
|
530
|
+
git grep -rnE "setAttribute\('margin', |\.margin\s*="
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
Filter to `qr-code-ui` hosts only — `margin` is a legitimate global attribute on every other
|
|
534
|
+
element, so only rewrite a hit that is actually a `<qr-code-ui>` reference:
|
|
535
|
+
`setAttribute('margin', …)` → `setAttribute('quiet-zone', …)`; `el.margin = …` → `el.quietZone
|
|
536
|
+
= …`.
|
|
537
|
+
|
|
538
|
+
### Verify
|
|
539
|
+
|
|
540
|
+
```bash
|
|
541
|
+
git grep -nE '<qr-code-ui[^>]*\smargin=' # must be 0
|
|
542
|
+
npm run check # in-repo consumers; downstream: your app's build
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
---
|
|
546
|
+
|
|
547
|
+
<a id="upcoming--leading-scale-consolidation-adr-0052"></a>
|
|
548
|
+
## Shipped in `0.8.40` — leading-scale consolidation (ADR-0052)
|
|
549
|
+
|
|
550
|
+
**BREAKING, no aliases, ships in `0.8.40`.** [ADR-0052](../../docs/ops/adr/adr-0052-leading-scale-consolidation.md)
|
|
551
|
+
retires the legacy `--a-leading-*` family. `--a-font-leading-*` is now the
|
|
552
|
+
single canonical line-height scale.
|
|
553
|
+
|
|
554
|
+
**Why:** two leading-token families coexisted in `scale.css` with the same
|
|
555
|
+
step names resolving to *different* values (`--a-leading-snug` = `1.3` vs.
|
|
556
|
+
`--a-font-leading-snug` = `1.2`). A component author reaching for a leading
|
|
557
|
+
token had no obviously-correct choice — which is why a corpus-wide sweep
|
|
558
|
+
(gh#1298) found 55 component files reaching for a bare numeric literal
|
|
559
|
+
instead of either family. `--a-font-leading-*` is what the L2 role layer
|
|
560
|
+
already consumes and its shape (tightening as size grows) is the design
|
|
561
|
+
intent on record. One step closes its only gap: `--a-font-leading-none: 1`.
|
|
562
|
+
|
|
563
|
+
**No value-preserving aliases.** `snug`/`normal` name different values
|
|
564
|
+
across the two families — aliasing one name to the other would silently
|
|
565
|
+
restyle every consumer of the alias. Replacement table (value-nearest, not
|
|
566
|
+
name-preserving):
|
|
567
|
+
|
|
568
|
+
| Removed | Value | Replacement | Value |
|
|
569
|
+
|---|---|---|---|
|
|
570
|
+
| `--a-leading-none` | `1` | `--a-font-leading-none` | `1` |
|
|
571
|
+
| `--a-leading-tight` | `1.2` | `--a-font-leading-snug` | `1.2` |
|
|
572
|
+
| `--a-leading-snug` | `1.3` | `--a-font-leading-normal` | `1.35` |
|
|
573
|
+
| `--a-leading-normal` | `1.5` | `--a-font-leading-relaxed` | `1.5` |
|
|
574
|
+
|
|
575
|
+
A surviving `var(--a-leading-*)` reference goes invalid-at-computed-value-time
|
|
576
|
+
→ inherit (same failure shape as the `--a-font` alias removal in `0.8.23`).
|
|
577
|
+
|
|
578
|
+
### The same sweep also tokenized every other hardcoded typography literal
|
|
579
|
+
|
|
580
|
+
Beyond the legacy family, gh#1298's corpus sweep found — and tokenized —
|
|
581
|
+
every bare numeric `line-height`, `em`-literal `letter-spacing`, and numeric
|
|
582
|
+
`font-weight` in `packages/web-components/components/*/*.css`:
|
|
583
|
+
|
|
584
|
+
- **`line-height`** — mapped to the nearest `--a-font-leading-*` step. Both
|
|
585
|
+
`1.3` and `1.4` map to `--a-font-leading-normal` (`1.35`) — no new step was
|
|
586
|
+
minted (at the 12–14px sizes where these values appeared, ±0.05
|
|
587
|
+
line-height is below visual significance). A handful of `1.4` hits on
|
|
588
|
+
genuinely multi-line body/description copy were mapped up to
|
|
589
|
+
`--a-font-leading-relaxed` (`1.5`) instead, case-by-case — see the sweep
|
|
590
|
+
PR description for the enumerated list. `line-height: 0` (the
|
|
591
|
+
icon/line-box-collapse idiom used by `icon.css`, `swatch.css`,
|
|
592
|
+
`qr-code.css`, etc.) is **not** a typographic leading value and was left
|
|
593
|
+
untouched.
|
|
594
|
+
- **`letter-spacing`** — mapped to the nearest `--a-font-tracking-*` step;
|
|
595
|
+
`0.05em` (off-scale) maps to `--a-font-tracking-wide` (`0.04em`), same
|
|
596
|
+
nearest-step logic as the leading family.
|
|
597
|
+
- **`font-weight`** — all hits were already on-scale and map mechanically to
|
|
598
|
+
`--a-weight-*` (`500`→medium, `600`→semibold, `700`→bold).
|
|
599
|
+
|
|
600
|
+
### A mechanized gate follows the sweep
|
|
601
|
+
|
|
602
|
+
`npm run check:typography-tokens` (wired into the `npm run check` aggregate)
|
|
603
|
+
fails on any bare numeric `line-height`, `em`-literal `letter-spacing`, or
|
|
604
|
+
numeric `font-weight` reappearing in `packages/web-components/components/*/*.css`
|
|
605
|
+
— mirroring the existing brand-chrome/foundation-layer audit gates — so the
|
|
606
|
+
parallel scale (and the literal-reaching it caused) cannot silently
|
|
607
|
+
reaccumulate.
|
|
608
|
+
|
|
609
|
+
### Mechanical sweep
|
|
610
|
+
|
|
611
|
+
```bash
|
|
612
|
+
git grep -nE -- '--a-leading-(none|tight|snug|normal)\b'
|
|
613
|
+
```
|
|
614
|
+
|
|
615
|
+
Apply the replacement table above at each hit — do not blind-`sed`, since
|
|
616
|
+
`snug`/`normal` map to *different* replacement names than their own name
|
|
617
|
+
would suggest.
|
|
618
|
+
|
|
619
|
+
### Verify
|
|
620
|
+
|
|
621
|
+
```bash
|
|
622
|
+
git grep -nE -- '--a-leading-(none|tight|snug|normal)\b' # must be 0
|
|
623
|
+
npm run check:typography-tokens # must exit 0
|
|
624
|
+
npm run check
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
---
|
|
628
|
+
|
|
629
|
+
<a id="upcoming--toggle-option-ui-drops-the-legacy-data-selected-stamp-0840-adr-0056"></a>
|
|
630
|
+
## Shipped in `0.8.40` — `toggle-option-ui` drops the legacy `data-selected` stamp (ADR-0056)
|
|
631
|
+
|
|
632
|
+
**BREAKING, no deprecation alias.** [ADR-0056](../../docs/ops/adr/adr-0056-selection-item-selected-convention.md)'s
|
|
633
|
+
breaking half removes `<toggle-group-ui>`'s legacy `data-selected` attribute
|
|
634
|
+
stamp on its `<toggle-option-ui>` children. The declared, reflected `selected`
|
|
635
|
+
prop (shipped additively in `0.8.39`) is now the *only* current-state surface
|
|
636
|
+
— matching `<segment-ui>`'s existing convention.
|
|
637
|
+
|
|
638
|
+
**Migration:** any external CSS or script targeting `[data-selected]` on
|
|
639
|
+
`toggle-option-ui` must move to `[selected]` — same semantics, same timing,
|
|
640
|
+
just the attribute name. `toggle-group.css` itself already styled
|
|
641
|
+
`[selected]`; the removed stamp was a parallel, undocumented hook with no
|
|
642
|
+
declared API surface (invisible to the yaml SoT, the catalog, and the A2UI
|
|
643
|
+
grammar).
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
git grep -n "data-selected" -- '*.css' '*.js' '*.html' | grep -i toggle # must be 0
|
|
647
|
+
npm run check
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
---
|
|
651
|
+
|
|
652
|
+
<a id="upcoming--progress-ui-retires-variant-090-gh1370"></a>
|
|
653
|
+
## Shipped in `0.8.41` — `progress-ui` retires `variant` (gh#1370)
|
|
654
|
+
|
|
655
|
+
**BREAKING, no deprecation alias.** `<progress-ui>`'s `variant` prop
|
|
656
|
+
(`bar` | `spinner`) is removed — progress is bar-only. `<spinner-ui>`
|
|
657
|
+
owns circular loading indicators.
|
|
658
|
+
|
|
659
|
+
**Why:** `packages/web-components/MIGRATION.md:2125,2139` records the
|
|
660
|
+
original standalone spinner being merged INTO progress as
|
|
661
|
+
`variant="spinner"` in the old `@agent-ui-kit` → `@adia-ai` migration —
|
|
662
|
+
then a richer standalone `<spinner-ui>` (`arc`/`ring`/`dots`/`knight`,
|
|
663
|
+
`tone`, `paused`, `label`) was later re-added. Both shipped in the
|
|
664
|
+
catalog, so a "loading" intent had three valid answers instead of two
|
|
665
|
+
disjoint ones. Retiring the render mode from progress un-forks the
|
|
666
|
+
consolidation that was already undone once. Filed from the
|
|
667
|
+
catalog-regularity audit's C2 finding, [gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363).
|
|
668
|
+
|
|
669
|
+
**Migration:**
|
|
670
|
+
|
|
671
|
+
| Old | New |
|
|
672
|
+
|---|---|
|
|
673
|
+
| `<progress-ui variant="spinner">` | `<spinner-ui>` (`arc` is the closest visual match to the old rotating-arc spinner render; pick `ring`/`dots`/`knight` if the intent was different) |
|
|
674
|
+
| `<progress-ui variant="bar">` | drop the attribute — `bar` was already the default |
|
|
675
|
+
| `<progress-ui>` (no variant) | unchanged — already bar, already the default |
|
|
676
|
+
|
|
677
|
+
`<spinner-ui>` has no `value` prop — it is indeterminate-only. A
|
|
678
|
+
determinate use of `variant="spinner"` (if any existed) has no direct
|
|
679
|
+
spinner-ui equivalent; keep `<progress-ui>` and drop the `variant`
|
|
680
|
+
attribute instead (renders as a determinate bar).
|
|
681
|
+
|
|
682
|
+
**Find every affected consumer site with the repo's own scanner — not
|
|
683
|
+
ad-hoc grep** (a markup grep also fires on this very guide's worked
|
|
684
|
+
examples above, and misses double-quoted setters, multiline HTML
|
|
685
|
+
attributes, and whitespace variations around `=`):
|
|
686
|
+
|
|
687
|
+
```bash
|
|
688
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
689
|
+
```
|
|
690
|
+
|
|
691
|
+
`scripts/qa/contract-migration-scan.mjs` (gh#1405, shipped on `main`)
|
|
692
|
+
detects the `variant` removal from `progress.yaml` directly and
|
|
693
|
+
enumerates every markup consumer under `packages/`, `apps/`,
|
|
694
|
+
`playgrounds/`, `site/` — including corpus chunks — read from the two
|
|
695
|
+
git refs, so a dirty working tree never leaks into the report. Its own
|
|
696
|
+
tag-markup matching also fires on this guide's *shipped* copy
|
|
697
|
+
(`packages/web-components/MIGRATION.md`, which lives under `packages/`
|
|
698
|
+
and quotes `variant="spinner"` as a worked example above, not live
|
|
699
|
+
usage) — expect and disregard that one self-hit; any other reported
|
|
700
|
+
site is a real consumer to migrate. The scanner's markup-textual
|
|
701
|
+
matching does not cover JS `setAttribute()`/property-assignment call
|
|
702
|
+
sites (its own documented limitation) — grep those separately:
|
|
703
|
+
|
|
704
|
+
```bash
|
|
705
|
+
git grep -rnE "setAttribute\('variant', *'(bar|spinner)'\)"
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
Verify each hit's element is actually a `progress-ui` host before
|
|
709
|
+
rewriting — the same discipline as the variant/color/tone convention
|
|
710
|
+
cut's own sweep above.
|
|
711
|
+
|
|
712
|
+
### Verify
|
|
713
|
+
|
|
714
|
+
```bash
|
|
715
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref> # only the MIGRATION.md self-hit, no other sites
|
|
716
|
+
git grep -rnE "setAttribute\('variant', *'(bar|spinner)'\)" # review each hit manually
|
|
717
|
+
npm run check
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
<a id="upcoming--input-ui-trims-type-enum-090-gh1381"></a>
|
|
723
|
+
## Shipped in `0.8.41` — `input-ui` trims `type` enum (gh#1381)
|
|
724
|
+
|
|
725
|
+
**BREAKING, no deprecation alias.** `<input-ui>`'s `type` enum is
|
|
726
|
+
trimmed to the six values it actually implements — `text` | `email` |
|
|
727
|
+
`password` | `number` | `tel` | `url`. `search`, `date`,
|
|
728
|
+
`datetime-local`, `time`, `month`, `week`, and `color` are removed.
|
|
729
|
+
|
|
730
|
+
**Why:** none of the seven removed values ever rendered a native
|
|
731
|
+
affordance — `input.class.js` only special-cases `password` (native
|
|
732
|
+
`<input>` for disc masking) and `number` (contenteditable + stepper
|
|
733
|
+
column); every other `type` value renders identically, a plain
|
|
734
|
+
contenteditable surface with no calendar, clock, swatch, or search
|
|
735
|
+
icon. `type="date"` was first-pass-VALID against the old enum but
|
|
736
|
+
functionally broken generation output — an LLM emitting it produces
|
|
737
|
+
markup that validates yet gives the user a bare text box where a date
|
|
738
|
+
picker was intended. Filed from the catalog-regularity audit's B10
|
|
739
|
+
finding, [gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363).
|
|
740
|
+
|
|
741
|
+
**Migration:**
|
|
742
|
+
|
|
743
|
+
| Old | New |
|
|
744
|
+
|---|---|
|
|
745
|
+
| `<input-ui type="search">` | `<search-ui>` (built-in magnifying-glass icon, clear button, debounced `search` event) |
|
|
746
|
+
| `<input-ui type="date">` | `<calendar-picker-ui>` (single-date, day granularity) |
|
|
747
|
+
| `<input-ui type="month">` / `type="week"` | `<calendar-picker-ui>` — no dedicated month/week-granularity primitive exists in the catalog; day granularity is the closest routed primitive |
|
|
748
|
+
| `<input-ui type="datetime-local">` | `<datetime-picker-ui>` |
|
|
749
|
+
| `<input-ui type="time">` | `<time-picker-ui>` |
|
|
750
|
+
| `<input-ui type="color">` | `<color-input-ui>` (compact form-row swatch + popover) — or `<color-picker-ui>` directly for a full-surface editor (Tokens-Studio-style canvas) |
|
|
751
|
+
| `<input-ui>` (no type, or `text`/`email`/`password`/`number`/`tel`/`url`) | unchanged |
|
|
752
|
+
|
|
753
|
+
The routed primitives are NOT drop-in attribute-compatible with
|
|
754
|
+
`input-ui` — each has its own prop surface (e.g. `time-picker-ui`
|
|
755
|
+
expects ISO `HH:mm`/`HH:mm:ss`, `calendar-picker-ui` expects ISO
|
|
756
|
+
`YYYY-MM-DD`, `color-input-ui` emits both `hex` and `oklch` views).
|
|
757
|
+
Re-check `name`/`value`/`required`/`disabled` against the target
|
|
758
|
+
primitive's own yaml rather than assuming a mechanical attribute
|
|
759
|
+
carry-over.
|
|
760
|
+
|
|
761
|
+
**The repo's own scanner does not catch this class of change** —
|
|
762
|
+
`scripts/qa/contract-migration-scan.mjs`'s diff detection is scoped to
|
|
763
|
+
a yaml losing a `props`/`tokens` key or its `tag:` field (its own
|
|
764
|
+
documented v1 scope); narrowing an existing prop's `enum:` list is
|
|
765
|
+
invisible to it, since the `type` prop key itself is untouched. Find
|
|
766
|
+
affected sites with the repo's established multiline-capable sweep
|
|
767
|
+
recipe instead (§14.5's precedent — `git grep` is line-based, so a
|
|
768
|
+
`[^>]*` character class cannot cross a newline and misses a multi-line
|
|
769
|
+
opening tag; `rg -nU` is required, quote-aware, tag-scoped, and
|
|
770
|
+
excludes the historical/generated surfaces that legitimately still
|
|
771
|
+
quote the old markup as a worked example — this guide's own table
|
|
772
|
+
above, its shipped copy, `CHANGELOG*.md`, `dist/`, and `.claude/docs/`
|
|
773
|
+
itself, which also covers the frozen `.claude/docs/specs/*.md`
|
|
774
|
+
planning records):
|
|
775
|
+
|
|
776
|
+
```bash
|
|
777
|
+
rg -nU '<input-ui[^>]*type="(search|date|datetime-local|time|month|week|color)"' \
|
|
778
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
779
|
+
-g '!.claude/docs/**'
|
|
780
|
+
```
|
|
781
|
+
|
|
782
|
+
Verify each hit's element is actually an `input-ui` host, then migrate
|
|
783
|
+
per the table above. The corpus harvest (`npm run harvest:chunks`)
|
|
784
|
+
independently re-validates every chunk against the updated catalog
|
|
785
|
+
schema and will name any consumer still using a removed `type` value
|
|
786
|
+
as a chunk-validation failure — run it after the yaml edit and before
|
|
787
|
+
opening a PR; it is a second, stricter check this scanner's own
|
|
788
|
+
limitation makes necessary for enum-narrowing changes, but it is NOT a
|
|
789
|
+
substitute for the sweep above — the harvest only validates chunks the
|
|
790
|
+
corpus actually harvests (annotated `data-chunk` regions), so a
|
|
791
|
+
non-harvested consumer (a component's own `.examples.html` demo, a
|
|
792
|
+
JS-composed internal template like `search.class.js`'s own former
|
|
793
|
+
`<input-ui type="search">` stamp) needs the direct sweep to be found at
|
|
794
|
+
all.
|
|
795
|
+
|
|
796
|
+
### Verify
|
|
797
|
+
|
|
798
|
+
```bash
|
|
799
|
+
rg -nU '<input-ui[^>]*type="(search|date|datetime-local|time|month|week|color)"' \
|
|
800
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
801
|
+
-g '!.claude/docs/**' # must be 0 hits (exit 1, rg's "no match" signal) after migrating real sites
|
|
802
|
+
npm run harvest:chunks # 0 catalog:input validation failures
|
|
803
|
+
npm run check
|
|
804
|
+
```
|
|
805
|
+
|
|
806
|
+
---
|
|
807
|
+
|
|
808
|
+
<a id="upcoming--web-modules-data--state-converges-to-bare-attributes-090-gh1332"></a>
|
|
809
|
+
## Shipped in `0.8.41` — web-modules `data-*` state converges to bare attributes (gh#1332)
|
|
810
|
+
|
|
811
|
+
**BREAKING, no deprecation alias.** Two web-modules' declared `states:`
|
|
812
|
+
entries used a private `data-*` stamp where a sibling state on the SAME
|
|
813
|
+
component already used a bare state attribute — an inconsistency the
|
|
814
|
+
[data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332)
|
|
815
|
+
(Category A) generalizes ADR-0056's rule to catch: API-conceptual state a
|
|
816
|
+
consumer/generator can see in the yaml `states:` list belongs on a bare
|
|
817
|
+
attribute, never hidden behind `data-*`.
|
|
818
|
+
|
|
819
|
+
| Component | Old | New |
|
|
820
|
+
|---|---|---|
|
|
821
|
+
| `<integrations-page-ui>` | `[data-empty-search]` | `[empty-search]` |
|
|
822
|
+
| `<integrations-page-ui>` | `[data-empty-data]` | `[empty-data]` |
|
|
823
|
+
| `<onboarding-checklist-ui>` | `[data-complete]` | `[complete]` |
|
|
824
|
+
|
|
825
|
+
**Why:** `integrations-page-ui`'s `states:` list already declares
|
|
826
|
+
`loading` with `attribute: loading` (bare) right next to `empty-search`/
|
|
827
|
+
`empty-data`, which used `attribute: data-empty-search`/
|
|
828
|
+
`data-empty-data` — same kind of declared, documented state, two
|
|
829
|
+
different attribute grammars on one component. `onboarding-checklist-ui`
|
|
830
|
+
has the identical shape: `collapsed` and `dismissed` both reflect bare
|
|
831
|
+
attributes (`collapsed`, `hidden`) while `complete` alone used
|
|
832
|
+
`data-complete`. Neither was ever declared in the component's `props:`
|
|
833
|
+
section — both were computed, read-only states set directly via
|
|
834
|
+
`setAttribute`/`removeAttribute`, styling hooks in the same family as
|
|
835
|
+
`loading`/`collapsed`, just minted with the wrong prefix.
|
|
836
|
+
|
|
837
|
+
**Find every affected consumer site with the repo's own scanner, plus
|
|
838
|
+
the multiline-capable manual sweep** (established in the `input-ui`
|
|
839
|
+
`type`-enum rider above, and again at gh#1414/gh#1420) — a line-based
|
|
840
|
+
`git grep` misses multi-line opening tags, and a bracketed-selector-only
|
|
841
|
+
search misses a JS consumer reading the raw attribute name via
|
|
842
|
+
`getAttribute`/`setAttribute`/`hasAttribute`/`dataset`, not a CSS
|
|
843
|
+
selector:
|
|
844
|
+
|
|
845
|
+
```bash
|
|
846
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
847
|
+
# contract-migration-scan's v1 scope is props:/tokens:/tag: — states: entries
|
|
848
|
+
# are outside it (no props/tag/token key is lost here), so treat its report
|
|
849
|
+
# as a first pass, not the full sweep for THIS migration; the rg sweep below
|
|
850
|
+
# is what actually covers it.
|
|
851
|
+
rg -nU '\[data-empty-search\]|\[data-empty-data\]|\[data-complete\]|data-empty-search|data-empty-data|data-complete' \
|
|
852
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
853
|
+
-g '!.claude/docs/**'
|
|
854
|
+
```
|
|
855
|
+
|
|
856
|
+
The raw-name alternation catches `el.getAttribute('data-empty-search')` /
|
|
857
|
+
`el.dataset.emptySearch` (dataset reads reflect through the raw attribute
|
|
858
|
+
name in the DOM, not the camelCase JS property) alongside the bracketed
|
|
859
|
+
CSS-selector form; the bracketed alternation stays for a selector split
|
|
860
|
+
across a line the raw form's word boundary might otherwise merge with a
|
|
861
|
+
neighboring token. `integrations-page-ui`'s unrelated `data-empty-reason`
|
|
862
|
+
(an internal part-scoped value attribute, not this `states:` entry) is
|
|
863
|
+
intentionally excluded from both alternations — do not add it.
|
|
864
|
+
|
|
865
|
+
**Migrate each verified hit** — review before rewriting; the portable
|
|
866
|
+
form below avoids `sed -i`'s BSD-vs-GNU flag divergence (BSD `sed -i`
|
|
867
|
+
requires an explicit, even empty, backup-suffix argument; GNU `sed -i`
|
|
868
|
+
treats a bare backup-suffix argument as the script itself and errors —
|
|
869
|
+
the two are not drop-in compatible, so a script this guide hands to
|
|
870
|
+
`rg -l | xargs` for consumers on either platform needs a wrapper neither
|
|
871
|
+
flavor chokes on):
|
|
872
|
+
|
|
873
|
+
```bash
|
|
874
|
+
rg -l '\[data-empty-search\]|\[data-empty-data\]|data-empty-search|data-empty-data' \
|
|
875
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
|
|
876
|
+
| xargs perl -pi -e 's/data-empty-search/empty-search/g; s/data-empty-data/empty-data/g'
|
|
877
|
+
rg -l '\[data-complete\]|data-complete' \
|
|
878
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
|
|
879
|
+
| xargs perl -pi -e 's/data-complete/complete/g'
|
|
880
|
+
```
|
|
881
|
+
|
|
882
|
+
### Verify
|
|
883
|
+
|
|
884
|
+
```bash
|
|
885
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
886
|
+
rg -nU '\[data-empty-search\]|\[data-empty-data\]|\[data-complete\]|data-empty-search|data-empty-data|data-complete' \
|
|
887
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
888
|
+
-g '!.claude/docs/**' # must be 0 hits (exit 1, rg's "no match" signal) after migrating real sites
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
<a id="upcoming--primitive-tier-data--state-converges-to-bare-attributes-090-gh1332-2"></a>
|
|
892
|
+
## Shipped in `0.8.41` — primitive-tier `data-*` state converges to bare attributes (gh#1332-2)
|
|
893
|
+
|
|
894
|
+
**BREAKING, no deprecation alias.** The residual primitive-tier round of
|
|
895
|
+
the [data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332)
|
|
896
|
+
(Category A), covering the ~25 primitives left over after the web-modules
|
|
897
|
+
round above. Same rule: API-conceptual state a consumer/generator can see
|
|
898
|
+
in the yaml `states:` list belongs on a bare attribute, never hidden
|
|
899
|
+
behind `data-*`.
|
|
900
|
+
|
|
901
|
+
| Component | Old | New |
|
|
902
|
+
|---|---|---|
|
|
903
|
+
| `<feed-item-ui>` | `[data-open]` | `[open]` |
|
|
904
|
+
| `<feed-item-ui>` | `[data-closing]` | `[closing]` |
|
|
905
|
+
| `<feed-item-ui>` | `[data-queued]` | `[queued]` |
|
|
906
|
+
| `<slider-ui>` | `[data-dragging]` | `[dragging]` |
|
|
907
|
+
| `<range-ui>` | `[data-dragging]` | `[dragging]` |
|
|
908
|
+
| `<pane-ui>` | `[data-resizing]` | `[resizing]` |
|
|
909
|
+
| `<chart-ui>` | `[data-has-data]` | `[has-data]` |
|
|
910
|
+
| `<select-ui>` | `[data-multi-chips]` | *(removed — no successor; see below)* |
|
|
911
|
+
| `<qr-code-ui>` | `[data-error]` | `[error]` |
|
|
912
|
+
| `<table-ui>` | `[data-selected]` (body rows) | `[aria-selected="true"]` |
|
|
913
|
+
| `<pagination-ui>` | `[data-active]` (page buttons) | `[aria-current="page"]` |
|
|
914
|
+
| `<tags-input-ui>` | `[data-empty]` (inline input) | *(removed — key off the host's declared `:not([editing])` inverse)* |
|
|
915
|
+
| `<input-ui>` | `[data-number]` (field div) | *(removed — key off the declared, reflected host `[type="number"]`)* |
|
|
916
|
+
|
|
917
|
+
**Why:** `feed-item-ui`'s open/closing lifecycle and `feed-ui`'s
|
|
918
|
+
above-`[max]` queue marker, `slider-ui`/`range-ui`'s mid-drag flag,
|
|
919
|
+
`pane-ui`'s mid-resize flag, and `chart-ui`'s has-data flag were each set
|
|
920
|
+
directly via `this.setAttribute`/`removeAttribute` on the host with no
|
|
921
|
+
`props:`/`states:` declaration — private stamps for genuine, observable
|
|
922
|
+
lifecycle state. `pane-ui[resizing]` matches the bare `[resizing]`
|
|
923
|
+
convention `admin-sidebar-ui`/`chat-sidebar-ui` already carry (fixed in
|
|
924
|
+
the web-modules round above, PR #1438) rather than minting a new name.
|
|
925
|
+
|
|
926
|
+
`select-ui[data-multi-chips]` is different in kind: it was a pure
|
|
927
|
+
*derived* cache of two attributes ALREADY declared and reflected —
|
|
928
|
+
`[multiple]` and `[summary-label]` — so there is no successor attribute;
|
|
929
|
+
consumer CSS/JS keying off the private mirror should key off the compound
|
|
930
|
+
selector `[multiple]:not([summary-label])` (or the equivalent JS property
|
|
931
|
+
check) directly instead.
|
|
932
|
+
|
|
933
|
+
The residual-round entries follow the same two shapes. `qr-code-ui`'s
|
|
934
|
+
`error` state was already yaml-declared but mapped to `attribute:
|
|
935
|
+
data-error` — the mapping converged to bare `[error]` (the same shape as
|
|
936
|
+
the web-modules round's `integrations-page-ui` converge). `table-ui`'s
|
|
937
|
+
body-row `[data-selected]` and `pagination-ui`'s page-button
|
|
938
|
+
`[data-active]` were private duplicates of an ARIA attribute set on the
|
|
939
|
+
SAME element in the same code path (`aria-selected="true"` /
|
|
940
|
+
`aria-current="page"`) — the ARIA attribute alone now carries the state
|
|
941
|
+
(PR #1438's `admin-roster` `aria-checked` precedent). `tags-input-ui`'s
|
|
942
|
+
inline-input `[data-empty]` was the exact inverse of the host's declared
|
|
943
|
+
`[editing]` state, and `input-ui`'s `[data-number]` field marker was a
|
|
944
|
+
mirror of the declared, reflected `[type="number"]` — both dropped with
|
|
945
|
+
no successor, `select-ui`-style.
|
|
946
|
+
|
|
947
|
+
**Find every affected consumer site:**
|
|
948
|
+
|
|
949
|
+
```bash
|
|
950
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
951
|
+
# props:/tokens:/tag: scope only — none of these are prop/tag/token
|
|
952
|
+
# changes (states: entries + one dropped private mirror), so treat this
|
|
953
|
+
# as a first pass; the rg sweep below is what actually covers it.
|
|
954
|
+
# Attribute forms (HTML/CSS/JS strings) — word-bounded so e.g. `data-opening`
|
|
955
|
+
# or another component's own `data-error` prose doesn't false-positive:
|
|
956
|
+
rg -nU 'data-(open|closing|queued|dragging|resizing|has-data|multi-chips|selected|active|empty|error|number)\b' \
|
|
957
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
958
|
+
-g '!.claude/docs/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
|
|
959
|
+
# dataset.* property forms (JS) — the camelCase twins of the same attributes:
|
|
960
|
+
rg -nU 'dataset\.(open|closing|queued|dragging|resizing|hasData|multiChips|selected|active|empty|error|number)\b' \
|
|
961
|
+
-g '!**/dist/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
|
|
962
|
+
```
|
|
963
|
+
|
|
964
|
+
Review each hit before rewriting — `data-open`/`data-closing` also appear
|
|
965
|
+
verbatim on `modal-ui`/`drawer-ui`'s own INTERNAL `<dialog slot="dialog">`
|
|
966
|
+
anatomy child (never on those hosts, and unrelated to this migration —
|
|
967
|
+
those two already expose a real `open` prop; the private child-level
|
|
968
|
+
stamp is an animation-timing implementation detail, left as-is), and
|
|
969
|
+
`data-dragging` also appears on `swiper-ui`'s internal track child (same
|
|
970
|
+
shape, also left as-is). Only the eight HOST-level attributes in the
|
|
971
|
+
table above moved.
|
|
972
|
+
|
|
973
|
+
**Migrate each verified hit:**
|
|
974
|
+
|
|
975
|
+
```bash
|
|
976
|
+
# Word-bounded exact tokens only (\b guards partial identifiers like
|
|
977
|
+
# `data-opening`), generated artifacts excluded (regenerate those with the
|
|
978
|
+
# repo's own commands afterwards — never rewrite them in place):
|
|
979
|
+
EXCL=(-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**'
|
|
980
|
+
-g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json' -g '!site-a2ui/**'
|
|
981
|
+
-g '!**/corpus/chunks/**')
|
|
982
|
+
rg -l 'data-(open|closing|queued)\b' "${EXCL[@]}" \
|
|
983
|
+
-g '!**/components/modal/**' -g '!**/components/drawer/**' \
|
|
984
|
+
| xargs perl -pi -e 's/\bdata-open\b/open/g; s/\bdata-closing\b/closing/g; s/\bdata-queued\b/queued/g'
|
|
985
|
+
rg -l 'data-dragging\b' "${EXCL[@]}" -g '!**/components/swiper/**' \
|
|
986
|
+
| xargs perl -pi -e 's/\bdata-dragging\b/dragging/g'
|
|
987
|
+
rg -l 'data-resizing\b' "${EXCL[@]}" \
|
|
988
|
+
| xargs perl -pi -e 's/\bdata-resizing\b/resizing/g'
|
|
989
|
+
rg -l 'data-has-data\b' "${EXCL[@]}" \
|
|
990
|
+
| xargs perl -pi -e 's/\bdata-has-data\b/has-data/g'
|
|
991
|
+
rg -l 'data-error\b' "${EXCL[@]}" \
|
|
992
|
+
| xargs perl -pi -e 's/\bdata-error\b/error/g' # qr-code-ui sites only — review hits first, other components keep their own data-error
|
|
993
|
+
# table-ui [data-selected] → [aria-selected="true"], pagination-ui
|
|
994
|
+
# [data-active] → [aria-current="page"], tags-input-ui [data-empty] →
|
|
995
|
+
# :scope:not([editing]) …, input-ui [data-number] → [type="number"] …:
|
|
996
|
+
# ARIA/compound successors — rewrite these selector-by-selector by hand,
|
|
997
|
+
# there is no mechanical 1:1 attribute swap.
|
|
998
|
+
# After all rewrites, regenerate derived artifacts:
|
|
999
|
+
node scripts/build/components.mjs && node scripts/build/site-a2ui.mjs --stale && npm run harvest:chunks
|
|
1000
|
+
# [data-multi-chips] has no successor attribute — rewrite the selector/check
|
|
1001
|
+
# by hand to [multiple]:not([summary-label]) (CSS) or the equivalent
|
|
1002
|
+
# `el.multiple && !el.summaryLabel` (JS), there is no mechanical 1:1 swap.
|
|
1003
|
+
```
|
|
1004
|
+
|
|
1005
|
+
### Verify
|
|
1006
|
+
|
|
1007
|
+
```bash
|
|
1008
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1009
|
+
rg -nU 'data-(open|closing|queued|dragging|resizing|has-data|multi-chips)\b|dataset\.(open|closing|queued|dragging|resizing|hasData|multiChips)\b' \
|
|
1010
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
1011
|
+
-g '!.claude/docs/**' -g '!**/components/modal/**' -g '!**/components/drawer/**' \
|
|
1012
|
+
-g '!**/components/swiper/**' -g '!*.a2ui.json' -g '!custom-elements.json' \
|
|
1013
|
+
-g '!catalog*.json' # must be 0 hits (exit 1) after migrating real sites
|
|
1014
|
+
# and, scoped to each owning component's consumers (other components keep
|
|
1015
|
+
# their own same-named markers): qr-code data-error / table data-selected /
|
|
1016
|
+
# pagination data-active / tags-input data-empty / input data-number, plus
|
|
1017
|
+
# dataset.{error,selected,active,empty,number} accesses on those elements.
|
|
1018
|
+
npm run check
|
|
1019
|
+
```
|
|
1020
|
+
|
|
1021
|
+
`data-grid`/`data-resize` are explicitly OUT of this round — both are
|
|
1022
|
+
genuine, documented public APIs (admin-shell's 2/3-column layout helper;
|
|
1023
|
+
admin-sidebar/chat-sidebar/editor-sidebar's drag handle) that ADR-0060
|
|
1024
|
+
names as can't-move-without-a-migration this pass; they carry over to the
|
|
1025
|
+
`0.9.0` ADR-0053/0056 breaking-rename wave, not this ticket.
|
|
1026
|
+
|
|
1027
|
+
<a id="upcoming--image-ui-loaderror-states-declared--converge-to-bare-attributes-090-gh1464"></a>
|
|
1028
|
+
## Shipped in `0.8.41` — image-ui load/error states declared + converge to bare attributes (gh#1464)
|
|
1029
|
+
|
|
1030
|
+
**BREAKING, no deprecation alias.** The final residue of the
|
|
1031
|
+
[data-* usage sweep](https://github.com/adiahealth/gen-ui-kit/issues/1332) —
|
|
1032
|
+
deferred out of the residual round above (PR #1463) because, unlike that
|
|
1033
|
+
round's entries, `image-ui`'s load/error attributes were never yaml-declared
|
|
1034
|
+
at all.
|
|
1035
|
+
|
|
1036
|
+
| Component | Old | New |
|
|
1037
|
+
|---|---|---|
|
|
1038
|
+
| `<image-ui>` | `[data-loaded]` | `[loaded]` |
|
|
1039
|
+
| `<image-ui>` | `[data-error]` | `[error]` |
|
|
1040
|
+
|
|
1041
|
+
**Why:** `image.class.js` set `data-loaded`/`data-error` directly via
|
|
1042
|
+
`this.setAttribute`/`removeAttribute` on the host with no `props:`/`states:`
|
|
1043
|
+
declaration — genuine, observable load-lifecycle state (the image's
|
|
1044
|
+
`load`/`error` events, including the gh#999 missed-load-race guard) hidden
|
|
1045
|
+
behind an undeclared private stamp. `image.yaml` now declares both as
|
|
1046
|
+
`states:` entries with bare `attribute:` mappings, matching `qr-code-ui`'s
|
|
1047
|
+
own `error` state (converged to bare `[error]` in the residual round
|
|
1048
|
+
above). `image-ui`'s unrelated `[data-overlay]` skeleton-proximity marker
|
|
1049
|
+
(gh#1362, an implementation-detail stamp on the composed `skeleton-ui`
|
|
1050
|
+
child, not a declared host state) is untouched.
|
|
1051
|
+
|
|
1052
|
+
**`data-msg-*` disposition (same ticket, non-breaking):** the
|
|
1053
|
+
validation-message config family (`data-msg-required`/`pattern`/
|
|
1054
|
+
`minlength`/`maxlength`/`min`/`max`/`bad-input`, read by `core/form.js`'s
|
|
1055
|
+
shared `UIFormElement` mixin across `input`/`select`/`tags-input`/`code`/
|
|
1056
|
+
`date-range-picker`/`datetime-picker`/`payment-method-form`) is **exempt** —
|
|
1057
|
+
it stays `data-*` with no yaml declaration and no attribute change. It is
|
|
1058
|
+
consumer-authored config the component only ever *reads* (never host-
|
|
1059
|
+
reflected state), and the read path is one shared mixin spanning 7+
|
|
1060
|
+
components with no single owning yaml SoT to declare it against. Full
|
|
1061
|
+
rationale: `primitive-authoring/references/yaml-contract.md`'s new
|
|
1062
|
+
`data-msg-*` section (ADR-0060 §Decision 3 routes this exact family here
|
|
1063
|
+
for its converge-or-ratify call). No consumer action needed for this half.
|
|
1064
|
+
|
|
1065
|
+
**Find every affected consumer site:**
|
|
1066
|
+
|
|
1067
|
+
```bash
|
|
1068
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1069
|
+
# states: entry, not a prop/tag/token change — treat the scan as a first
|
|
1070
|
+
# pass; the rg sweep below is what actually covers it. Word-bounded so a
|
|
1071
|
+
# same-named marker on another component (qr-code-ui's own already-bare
|
|
1072
|
+
# `error`, canvas-ui/agent-reasoning-ui's own `data-error`) doesn't
|
|
1073
|
+
# false-positive — review each hit, only image-ui sites move:
|
|
1074
|
+
rg -nU 'data-(loaded|error)\b' \
|
|
1075
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
1076
|
+
-g '!.claude/docs/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
|
|
1077
|
+
rg -nU 'dataset\.(loaded|error)\b' \
|
|
1078
|
+
-g '!**/dist/**' -g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json'
|
|
1079
|
+
```
|
|
1080
|
+
|
|
1081
|
+
**Migrate each verified `image-ui` hit:**
|
|
1082
|
+
|
|
1083
|
+
```bash
|
|
1084
|
+
rg -l 'data-loaded\b' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
|
|
1085
|
+
-g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json' \
|
|
1086
|
+
| xargs perl -pi -e 's/\bdata-loaded\b/loaded/g'
|
|
1087
|
+
# data-error: review hits first — qr-code-ui, canvas-ui, agent-reasoning-ui,
|
|
1088
|
+
# construct-canvas and error-shake keep their OWN data-error/data-error-*
|
|
1089
|
+
# markers unchanged; only image-ui sites move:
|
|
1090
|
+
rg -l 'data-error\b' -g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' \
|
|
1091
|
+
-g '!*.a2ui.json' -g '!custom-elements.json' -g '!catalog*.json' \
|
|
1092
|
+
-g '!**/components/qr-code/**' -g '!**/components/canvas/**' \
|
|
1093
|
+
-g '!**/components/agent-reasoning/**' -g '!**/traits/error-shake/**' \
|
|
1094
|
+
-g '!**/construct-canvas/**' \
|
|
1095
|
+
| xargs perl -pi -e 's/\bdata-error\b/error/g'
|
|
1096
|
+
node scripts/build/components.mjs && node scripts/build/site-a2ui.mjs --stale && npm run harvest:chunks
|
|
1097
|
+
```
|
|
1098
|
+
|
|
1099
|
+
### Verify
|
|
1100
|
+
|
|
1101
|
+
```bash
|
|
1102
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1103
|
+
rg -nU 'data-(loaded|error)\b' -g '!*CHANGELOG*.md' -g '!**/dist/**' \
|
|
1104
|
+
-g '!*.examples.md' -g '!*MIGRATION*' -g '!.claude/docs/**' \
|
|
1105
|
+
-g '!**/components/qr-code/**' -g '!**/components/canvas/**' \
|
|
1106
|
+
-g '!**/components/agent-reasoning/**' -g '!**/traits/error-shake/**' \
|
|
1107
|
+
-g '!**/construct-canvas/**' -g '!*.a2ui.json' -g '!custom-elements.json' \
|
|
1108
|
+
-g '!catalog*.json' # must be 0 hits on image-ui specifically after migrating real sites
|
|
1109
|
+
npm run check
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
<a id="upcoming--action-item-ui-converges-onto-menu-item-uis-row-contract-090-gh1374"></a>
|
|
1113
|
+
## Shipped in `0.8.41` — `action-item-ui` converges onto `menu-item-ui`'s row contract (gh#1374)
|
|
1114
|
+
|
|
1115
|
+
**BREAKING, no deprecation alias, zero known consumer sites.**
|
|
1116
|
+
`<action-item-ui>` (the child of `<action-list-ui>`) gains a `subtitle`
|
|
1117
|
+
prop and `text`/`subtitle`/`trailing` slot overrides, converging its row
|
|
1118
|
+
contract exactly onto `<menu-item-ui>`'s (icon/text/subtitle/value/
|
|
1119
|
+
variant/disabled props; icon/text/subtitle/trailing slot overrides). The
|
|
1120
|
+
`variant` enum (`default`/`danger`) already converged separately in
|
|
1121
|
+
[gh#1417](https://github.com/adiahealth/gen-ui-kit/pull/1417) (#1363 B6)
|
|
1122
|
+
and is unaffected here.
|
|
1123
|
+
|
|
1124
|
+
**Why:** the catalog-regularity audit's C5 finding
|
|
1125
|
+
([gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363)) flagged
|
|
1126
|
+
`action-item-ui` as `menu-item-ui` minus `subtitle`, with no principled
|
|
1127
|
+
reason for the two row contracts to differ — action-items live inline in
|
|
1128
|
+
content surfaces, menu-items live inside `<menu-ui>` popovers, but the row
|
|
1129
|
+
anatomy itself (leading icon, label, optional secondary line, optional
|
|
1130
|
+
trailing shortcut/badge) is identical. Filed as
|
|
1131
|
+
[gh#1374](https://github.com/adiahealth/gen-ui-kit/issues/1374).
|
|
1132
|
+
|
|
1133
|
+
**Container-level decision (also C5):** whether `<list-ui>` should absorb
|
|
1134
|
+
`<action-list-ui>` as a fire-and-forget `action` mode was decided **NO** —
|
|
1135
|
+
the two are kept as separate components. `<list-ui selectable>` holds a
|
|
1136
|
+
persisted single selection (`selectedKey`/`aria-selected`, roving
|
|
1137
|
+
tabindex); `<action-list-ui>` always fires and never holds selection
|
|
1138
|
+
state — genuinely different interaction contracts, not one mode axis, and
|
|
1139
|
+
no existing implementation of an "action" mode exists on `list-ui` to
|
|
1140
|
+
converge onto (unlike the segmented/toggle-group case, C1, where the mode
|
|
1141
|
+
already existed under a different name). `list.yaml` and `action-list.yaml`
|
|
1142
|
+
each carry an a2ui rule cross-routing to the other so the decision is
|
|
1143
|
+
discoverable at generation time.
|
|
1144
|
+
|
|
1145
|
+
**Migration:**
|
|
1146
|
+
|
|
1147
|
+
| Old | New |
|
|
1148
|
+
|---|---|
|
|
1149
|
+
| `<action-item-ui icon="…" text="…" value="…">` | unchanged |
|
|
1150
|
+
| `<action-item-ui>` with an unnamed (default-slot) trailing child (e.g. a `<kbd>` shortcut hint) | add `slot="trailing"` to that child |
|
|
1151
|
+
| Anything reading `subtitle` | new, additive — no migration |
|
|
1152
|
+
|
|
1153
|
+
A monorepo-wide sweep at dispatch time (`rg -nU` across every
|
|
1154
|
+
`<action-item-ui>...</action-item-ui>` span, source + corpus chunks +
|
|
1155
|
+
examples, dist/generated excluded) found **zero** consumers with slotted
|
|
1156
|
+
children of any kind — every usage in this repo is
|
|
1157
|
+
self-closing/attribute-only. The default-slot retirement is therefore a
|
|
1158
|
+
contract change with no repo-internal migration to perform; it is
|
|
1159
|
+
documented here for any external consumer that had adopted the unnamed
|
|
1160
|
+
slot.
|
|
1161
|
+
|
|
1162
|
+
**Find every affected consumer site:**
|
|
1163
|
+
|
|
1164
|
+
```bash
|
|
1165
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1166
|
+
rg -nU '<action-item-ui[^>]*>[\s\S]*?</action-item-ui>' \
|
|
1167
|
+
-g '!**/dist/**' -g '!*.a2ui.json' -g '!*MIGRATION*' -g '!.claude/docs/**'
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
Any non-self-closing `<action-item-ui>` hit with slotted content that
|
|
1171
|
+
isn't `slot="icon"` needs `slot="trailing"` added.
|
|
1172
|
+
<a id="upcoming--global-attribute-shadowing-collision-sweep-090-gh1335"></a>
|
|
1173
|
+
## Shipped in `0.8.41` — global-attribute-shadowing collision sweep (gh#1335)
|
|
1174
|
+
|
|
1175
|
+
**BREAKING, no deprecation aliases.** gh#1327's build of the ADR-0053/0054
|
|
1176
|
+
`check:attribute-shadowing` gate surfaced 16 pre-existing component-local
|
|
1177
|
+
attributes that shadowed the global attribute grammar with divergent
|
|
1178
|
+
semantics — the same collision class ADR-0053/0054 fixed for
|
|
1179
|
+
`qr-code-ui[margin]`, `table-ui[density]`, and `chart-ui[radius]`, but never
|
|
1180
|
+
itself audited. gh#1335 also surfaced a 17th collision of its own, during
|
|
1181
|
+
this same build's follow-up audit (`dashboard-layout-ui[gap]` — never in the
|
|
1182
|
+
gate's original 16, since its shape wasn't caught by the gate's type-only
|
|
1183
|
+
check for the `gap`/`padding`/`margin` Scale roster). Of the 17 total tracked
|
|
1184
|
+
here, **15 are resolved** (12 renamed/converged — the original 11 plus the
|
|
1185
|
+
17th — and 3 exempted); **2 remain open** (both from the original 16 — see
|
|
1186
|
+
below).
|
|
1187
|
+
|
|
1188
|
+
### Renames / conversions (12 — 11 from the original 16 + the 17th collision)
|
|
1189
|
+
|
|
1190
|
+
| Component | Old | New | Notes |
|
|
1191
|
+
|---|---|---|---|
|
|
1192
|
+
| `header-ui` | `[padding]` (boolean) | `[padded]` | same boolean semantics; collided with the global Scale `[padding]`. |
|
|
1193
|
+
| `menu-ui` | `[gap]` (raw px) | `[offset]` | same numeric semantics; matches `popover-ui`'s own rename — both wrap the same `anchorPopover()` helper. |
|
|
1194
|
+
| `popover-ui` | `[gap]` (raw px) | `[offset]` | same numeric semantics; yaml already described it as "pixel offset". |
|
|
1195
|
+
| `skeleton-ui` | `[radius]` (enum) | `[corner-radius]` | same enum (`none/sm/md/lg/full`); mirrors `chart-ui`'s own `[corner-radius]` fix (ADR-0054). |
|
|
1196
|
+
| `image-ui` | `[radius]` (enum) | `[corner-radius]` | same enum (`sm/md/lg/full`); same rename as `skeleton-ui` above. |
|
|
1197
|
+
| `invoice-detail-ui` | `[density]` (`compact`/`standard`) | `[density]` (`compact`/`spacious`/unset) | `standard` retired (never a real forwarded state — the JS already treated it as unset); `spacious` gained for parity with the global grammar. |
|
|
1198
|
+
| `invoice-history-ui` | `[density]` (`compact`/`standard`/`comfortable`) | `[density]` (`compact`/`spacious`/unset) | `standard` retired, `comfortable` → `spacious` (a real behavioral remap, this component's `comfortable` genuinely meant the same as `spacious`). |
|
|
1199
|
+
| `dashboard-layout-ui` | `[density]` includes `comfortable` | `[density]` drops `comfortable` | **not** a `comfortable`→`spacious` remap — verified as dead code: `comfortable` set only `--a-density:1` with no gap-token override, functionally identical to the unset `""` state, not to `spacious` (`--a-density:1.15` + wider gap tokens). Converges onto `""` (the closest matching real behavior). |
|
|
1200
|
+
| `dashboard-layout-ui` | `[gap]` (numeric `1`-`6`) | `[band-gap]` | kept namespaced, not converged onto the global `[gap]` Scale — it sets a component-local token that never composed with the ambient `[size]`→`--a-gap` cascade, and covers a narrower range (1-6 vs. the global 0-16); a genuinely distinct, band-scoped concept. |
|
|
1201
|
+
| `text-ui` | `[weight]` includes `regular` | `[weight]` uses `normal` | spelling convergence onto the global Enum·semantic `[weight]` vocabulary. |
|
|
1202
|
+
| `text-ui` | `[text-align]` (`start`/`center`/`end`/`justify`) | `[text-align]` (`left`/`center`/`right`/`justify`) | converges onto the global physical vocabulary; `justify` is a genuine physical (non-directional) value and is now supported by the global `[text-align]` grammar itself (`packages/web-components/styles/api/text.css`), not just `text-ui`'s own local rule. |
|
|
1203
|
+
| `tags-input-ui` | `[transform]` (`lowercase`/`trim`/`strip-spaces`) | `[normalize]` | value-commit normalization is a different concept from the global CSS `[transform]` (uppercase/lowercase/capitalize/none display styling), not merely a colliding vocabulary. |
|
|
1204
|
+
|
|
1205
|
+
### New §11 exemptions (3, no code change)
|
|
1206
|
+
|
|
1207
|
+
`button-ui[color]`, `toggle-scheme-ui[color]`, and `text-ui[color]` are
|
|
1208
|
+
newly ratified `.claude/docs/specs/attribute-api-system.md` §11 rows —
|
|
1209
|
+
`[color]` on these three plays the ADR-0044/ADR-0064 FAMILY axis (a
|
|
1210
|
+
different grammar from the generic descriptive `[color]` the rest of the
|
|
1211
|
+
catalog uses), not a foreign value against that generic vocabulary. No
|
|
1212
|
+
markup changes — these were always valid, just undocumented as deliberate.
|
|
1213
|
+
|
|
1214
|
+
### Left open (2) — since ratified as §11 exemptions (ADR-0070, no code change)
|
|
1215
|
+
|
|
1216
|
+
Both were tracked in the gate's own `KNOWN_FINDINGS`, not fixed by this
|
|
1217
|
+
sweep — self-certifying an exemption with no ADR citation is exactly what
|
|
1218
|
+
§11's own contract forbids. ADR-0070 (gh#1500) has since ratified both as
|
|
1219
|
+
§11 rows, the same way ADR-0044/ADR-0064 closed the `[color]` rows above:
|
|
1220
|
+
|
|
1221
|
+
- **`qr-code-ui[color]`** — a free-form CSS color string, structurally
|
|
1222
|
+
identical to the ratified `swatch-ui`/`noodles-ui[color]` §11 exemption
|
|
1223
|
+
("the component's entire subject is a color").
|
|
1224
|
+
- **`icon-ui[weight]`** — Phosphor icon-render-style vocabulary
|
|
1225
|
+
(`thin/light/regular/bold/fill/duotone`), a different concept entirely
|
|
1226
|
+
from font-weight — same "different concept" shape as the other ratified
|
|
1227
|
+
exemptions.
|
|
1228
|
+
|
|
1229
|
+
No markup changes — like the three ADR-0044/ADR-0064 exemptions, these were
|
|
1230
|
+
always valid, just undocumented as deliberate.
|
|
1231
|
+
|
|
1232
|
+
### Migration
|
|
1233
|
+
|
|
1234
|
+
| Old | New |
|
|
1235
|
+
|---|---|
|
|
1236
|
+
| `<header-ui padding>` | `<header-ui padded>` |
|
|
1237
|
+
| `<menu-ui gap="N">` | `<menu-ui offset="N">` |
|
|
1238
|
+
| `<popover-ui gap="N">` | `<popover-ui offset="N">` |
|
|
1239
|
+
| `<skeleton-ui radius="X">` | `<skeleton-ui corner-radius="X">` |
|
|
1240
|
+
| `<image-ui radius="X">` | `<image-ui corner-radius="X">` |
|
|
1241
|
+
| `<invoice-detail-ui density="standard">` | drop the attribute (unset is the default) |
|
|
1242
|
+
| `<invoice-history-ui density="standard">` | drop the attribute |
|
|
1243
|
+
| `<invoice-history-ui density="comfortable">` | `<invoice-history-ui density="spacious">` |
|
|
1244
|
+
| `<dashboard-layout-ui density="comfortable">` | drop the attribute (was already behaviorally equivalent to unset) |
|
|
1245
|
+
| `<dashboard-layout-ui gap="N">` | `<dashboard-layout-ui band-gap="N">` |
|
|
1246
|
+
| `<text-ui weight="regular">` | `<text-ui weight="normal">` |
|
|
1247
|
+
| `<text-ui text-align="start">` | `<text-ui text-align="left">` |
|
|
1248
|
+
| `<text-ui text-align="end">` | `<text-ui text-align="right">` |
|
|
1249
|
+
| `<tags-input-ui transform="…">` | `<tags-input-ui normalize="…">` |
|
|
1250
|
+
|
|
1251
|
+
**Find every affected consumer site with the repo's own scanner — not
|
|
1252
|
+
ad-hoc grep:**
|
|
1253
|
+
|
|
1254
|
+
```bash
|
|
1255
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1256
|
+
```
|
|
1257
|
+
|
|
1258
|
+
The scanner's markup-textual matching does not cover JS
|
|
1259
|
+
`setAttribute()`/property-assignment call sites at all, or the
|
|
1260
|
+
enum-value-only renames (`weight="regular"→"normal"`,
|
|
1261
|
+
`text-align="start/end"→"left/right"`, `density="standard"/"comfortable"`) —
|
|
1262
|
+
the latter are value changes on an attribute whose NAME didn't change,
|
|
1263
|
+
outside the scanner's rename-detection shape. Sweep both classes with a
|
|
1264
|
+
tag-scoped `rg -nU`:
|
|
1265
|
+
|
|
1266
|
+
**Enum-value-only renames (markup):**
|
|
1267
|
+
|
|
1268
|
+
```bash
|
|
1269
|
+
rg -nU '<text-ui[^>]*weight="regular"'
|
|
1270
|
+
rg -nU '<text-ui[^>]*text-align="(start|end)"'
|
|
1271
|
+
rg -nU '<(invoice-detail-ui|invoice-history-ui)[^>]*density="(standard|comfortable)"'
|
|
1272
|
+
rg -nU '<dashboard-layout-ui[^>]*density="comfortable"'
|
|
1273
|
+
```
|
|
1274
|
+
|
|
1275
|
+
**JS `setAttribute()` / property-assignment call sites (for every renamed
|
|
1276
|
+
attribute — `padding`, `gap`, `radius`, `transform`, plus the enum-only
|
|
1277
|
+
renames above by attribute name):**
|
|
1278
|
+
|
|
1279
|
+
```bash
|
|
1280
|
+
rg -nU "setAttribute\('(padding|gap|radius|transform)', *['\"]" -g '*.js' -g '*.ts'
|
|
1281
|
+
rg -nU '\.(padding|gap|radius|transform)\s*=' -g '*.js' -g '*.ts'
|
|
1282
|
+
rg -nU "setAttribute\('(weight|text-align|density)', *['\"](regular|start|end|standard|comfortable)['\"]" -g '*.js' -g '*.ts'
|
|
1283
|
+
```
|
|
1284
|
+
|
|
1285
|
+
The `\.(padding|gap|radius|transform)\s*=` property-assignment pattern is
|
|
1286
|
+
necessarily broad (these are common English words used by unrelated
|
|
1287
|
+
objects/properties too) — review each hit's receiver is actually a
|
|
1288
|
+
`header-ui`/`menu-ui`/`popover-ui`/`skeleton-ui`/`image-ui`/
|
|
1289
|
+
`dashboard-layout-ui`/`tags-input-ui` element before rewriting, the same
|
|
1290
|
+
discipline the `progress-ui` migration entry's own `setAttribute()`
|
|
1291
|
+
sweep above already documents.
|
|
1292
|
+
|
|
1293
|
+
### Verify
|
|
1294
|
+
|
|
1295
|
+
```bash
|
|
1296
|
+
node scripts/build/components.mjs --verify # sidecars clean
|
|
1297
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1298
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1299
|
+
node scripts/audit/check-attribute-shadowing.mjs --strict # 0 untracked violations, exactly 2 known findings
|
|
1300
|
+
npm run check
|
|
1301
|
+
```
|
|
1302
|
+
|
|
1303
|
+
---
|
|
1304
|
+
|
|
1305
|
+
|
|
1306
|
+
<a id="upcoming--segmented-ui-gains-multiple-toggle-group-uitoggle-option-ui-deprecated-090-gh1369"></a>
|
|
1307
|
+
## Shipped in `0.8.41` — `segmented-ui` gains `[multiple]`; `toggle-group-ui`/`toggle-option-ui` deprecated (gh#1369)
|
|
1308
|
+
|
|
1309
|
+
**Additive, non-breaking — plus a soft deprecation with no removal.**
|
|
1310
|
+
`<segmented-ui>` gains a `multiple: Boolean` axis (default `false`).
|
|
1311
|
+
`<toggle-group-ui>` and `<toggle-option-ui>` are marked
|
|
1312
|
+
`status: deprecated` and log a one-time `console.warn` on connect; **both
|
|
1313
|
+
keep working exactly as before** — this is a recommended migration, not
|
|
1314
|
+
a forced break.
|
|
1315
|
+
|
|
1316
|
+
**Why:** the catalog-regularity audit's C1 finding —
|
|
1317
|
+
[gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363), its
|
|
1318
|
+
top-ranked candidate. `<toggle-group-ui>` already carried a `single`
|
|
1319
|
+
mode prop that made it behave like segmented (`toggle-group.yaml`);
|
|
1320
|
+
four components played one concept. `toggle-group-ui`/`toggle-option-ui`
|
|
1321
|
+
had **zero** corpus chunk files (segmented/segment: 19 each), so
|
|
1322
|
+
multi-select intents (filter chips, day-of-week pickers) retrieved
|
|
1323
|
+
nothing for toggle-group or mis-retrieved single-select segmented
|
|
1324
|
+
chunks. Merging the multi-select axis into segmented gives multi-select
|
|
1325
|
+
intents the same 19-chunk retrieval mass single-select already has, and
|
|
1326
|
+
removes the Segmented-vs-ToggleGroup decision rule that was taught
|
|
1327
|
+
redundantly across four separate a2ui rules.
|
|
1328
|
+
|
|
1329
|
+
**New API:** under `[multiple]`, `<segmented-ui>`'s `value` becomes a
|
|
1330
|
+
comma-separated set of selected `<segment-ui>` values — the same
|
|
1331
|
+
encoding `<toggle-group-ui>` and `<select-ui multiple>` already use.
|
|
1332
|
+
The sliding indicator (single-select's animated pill) is suppressed;
|
|
1333
|
+
each selected segment carries its own background instead
|
|
1334
|
+
(`--segment-bg-selected`). Keyboard model changes under `[multiple]`
|
|
1335
|
+
only: arrow keys move focus without selecting (a checkbox-toolbar
|
|
1336
|
+
model, `role="group"` / children `role="checkbox"`), Space/Enter
|
|
1337
|
+
toggles the focused segment. Single-select (`[multiple]` absent) is
|
|
1338
|
+
byte-identical to before — radiogroup model, arrow-move selects,
|
|
1339
|
+
sliding indicator.
|
|
1340
|
+
|
|
1341
|
+
**Migration:**
|
|
1342
|
+
|
|
1343
|
+
| Old | New |
|
|
1344
|
+
|---|---|
|
|
1345
|
+
| `<toggle-group-ui value="bold,italic">` + `<toggle-option-ui value="bold" text="Bold" icon="…">` children | `<segmented-ui multiple value="bold,italic">` + `<segment-ui value="bold" text="Bold" icon="…">` children — `value`/`text`/`icon`/`disabled` map directly, same comma-separated `value` encoding |
|
|
1346
|
+
| `<toggle-group-ui single value="…">` (toggle-group's own single-select mode prop) | `<segmented-ui value="…">` (no `[multiple]`) — segmented's native single-select mode, not a mode flag on the multi-select component |
|
|
1347
|
+
| `toggle-option-ui[selected]` CSS | `segment-ui[selected]` under a `segmented-ui[multiple]` ancestor |
|
|
1348
|
+
|
|
1349
|
+
**Behavioral gap: `[single]`'s clear-on-reclick has no segmented-ui
|
|
1350
|
+
equivalent.** `<toggle-group-ui single>` clears its selection (empty
|
|
1351
|
+
`value`) when the already-selected option is activated again
|
|
1352
|
+
(`toggle-group.class.js`'s `#toggle()`: `if (selected.has(optVal))
|
|
1353
|
+
selected.clear()`). `<segmented-ui>` single-select does not — it's
|
|
1354
|
+
standard radiogroup semantics, exactly one segment stays selected once
|
|
1355
|
+
a value is set; clicking the already-selected segment again is a
|
|
1356
|
+
no-op. `allow-empty` does **not** cover this gap either — it only
|
|
1357
|
+
suppresses the connect-time self-select of the first segment when the
|
|
1358
|
+
initial `value` is falsy, it has no effect on later clicks. Most
|
|
1359
|
+
`[single]` consumers don't rely on the clear affordance (it wasn't
|
|
1360
|
+
advertised as the toggle-group contract's headline behavior) — audit
|
|
1361
|
+
before assuming it's needed.
|
|
1362
|
+
|
|
1363
|
+
**If a `[single]` consumer relies on the clear-on-reclick affordance**,
|
|
1364
|
+
the migration has no built-in replacement — wire it yourself, and the
|
|
1365
|
+
listener phase matters. `segmented-ui`'s own click handler runs on the
|
|
1366
|
+
**bubble** phase (registered in `connected()`); a same-phase consumer
|
|
1367
|
+
listener that reads `el.value` to decide "was this a re-click" is
|
|
1368
|
+
**registration-order-fragile**: a bubble listener attached AFTER
|
|
1369
|
+
`connected()` already ran (the realistic case —
|
|
1370
|
+
`document.querySelector('segmented-ui').addEventListener(...)` on an
|
|
1371
|
+
already-mounted page) reads `el.value` **after** segmented-ui's own
|
|
1372
|
+
handler already overwrote it with the just-clicked value, so the check
|
|
1373
|
+
is true on every click, not just re-clicks — it would incorrectly
|
|
1374
|
+
clear a selection of a *different* segment too. Snapshot the
|
|
1375
|
+
pre-click value in a **capture-phase** listener instead — capture
|
|
1376
|
+
always runs before bubble, independent of registration order — then
|
|
1377
|
+
apply the clear in a microtask so it lands after segmented-ui's own
|
|
1378
|
+
bubble handler (and its `change` dispatch) have already committed the
|
|
1379
|
+
reselect:
|
|
1380
|
+
|
|
1381
|
+
```js
|
|
1382
|
+
el.addEventListener(
|
|
1383
|
+
'click',
|
|
1384
|
+
(e) => {
|
|
1385
|
+
const seg = e.target.closest('segment-ui');
|
|
1386
|
+
if (!seg) return;
|
|
1387
|
+
const clickedValue = seg.value || seg.getAttribute('value') || '';
|
|
1388
|
+
const wasAlreadySelected = clickedValue === el.value; // pre-click snapshot
|
|
1389
|
+
if (wasAlreadySelected) {
|
|
1390
|
+
queueMicrotask(() => {
|
|
1391
|
+
el.value = '';
|
|
1392
|
+
// segmented-ui already dispatched one `change` for the reselect;
|
|
1393
|
+
// re-dispatch so consumers see the final (cleared) state too.
|
|
1394
|
+
el.dispatchEvent(new CustomEvent('change', { bubbles: true, detail: { value: '' } }));
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
},
|
|
1398
|
+
{ capture: true },
|
|
1399
|
+
);
|
|
1400
|
+
```
|
|
1401
|
+
|
|
1402
|
+
**Find every affected consumer site with the repo's own scanner, plus
|
|
1403
|
+
the multiline-capable manual sweep** (established in the `input-ui`
|
|
1404
|
+
`type`-enum rider above, and again for this exact tag-rename shape at
|
|
1405
|
+
gh#1414) — a line-based `git grep` misses multi-line opening tags:
|
|
1406
|
+
|
|
1407
|
+
```bash
|
|
1408
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1409
|
+
rg -nU '<toggle-group-ui[^>]*>|<toggle-option-ui[^>]*>' \
|
|
1410
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
1411
|
+
-g '!.claude/docs/**'
|
|
1412
|
+
```
|
|
1413
|
+
|
|
1414
|
+
Both tags keep working — a positive hit is a candidate to migrate on
|
|
1415
|
+
your own schedule, not a broken build. Verify each hit's element is
|
|
1416
|
+
actually a `toggle-group-ui`/`toggle-option-ui` host before rewriting.
|
|
1417
|
+
|
|
1418
|
+
### Verify
|
|
1419
|
+
|
|
1420
|
+
```bash
|
|
1421
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1422
|
+
rg -nU '<toggle-group-ui[^>]*>|<toggle-option-ui[^>]*>' \
|
|
1423
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
1424
|
+
-g '!.claude/docs/**' # any hit is a migration candidate, not a failure — both tags still work
|
|
1425
|
+
npm run check
|
|
1426
|
+
```
|
|
1427
|
+
|
|
1428
|
+
---
|
|
1429
|
+
|
|
1430
|
+
<a id="upcoming--calendar-picker-ui-absorbs-datetime-picker-ui-behind-a-widened-precision-axis-090-gh1372"></a>
|
|
1431
|
+
## Shipped in `0.8.41` — `calendar-picker-ui` absorbs `datetime-picker-ui` behind a widened `precision` axis (gh#1372)
|
|
1432
|
+
|
|
1433
|
+
**Mostly additive + soft deprecation; two real breaking removals on `calendar-picker-ui` itself.**
|
|
1434
|
+
`<calendar-picker-ui>` gains a `precision` axis (`date` | `minute` | `second`,
|
|
1435
|
+
default `date` — unchanged behavior for every existing consumer that never
|
|
1436
|
+
set it) plus the props/events it needs when a time pane is on:
|
|
1437
|
+
`step`/`hour-cycle`/`locale` (active only when `precision` isn't `date`),
|
|
1438
|
+
and the `input`/`open`/`close`/`invalid` events (previously only `change`
|
|
1439
|
+
existed). `<datetime-picker-ui>` is now marked `status: deprecated` and
|
|
1440
|
+
implemented as a thin `UICalendarPicker` subclass (`precision="minute"` by
|
|
1441
|
+
default) rather than an independent primitive — it keeps working
|
|
1442
|
+
unchanged. Filed from the catalog-regularity audit's C3c finding,
|
|
1443
|
+
[gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363) (C3d
|
|
1444
|
+
sibling-contract convergence folded into the same build).
|
|
1445
|
+
|
|
1446
|
+
**Why:** `datetime-picker-ui` was structurally `calendar-picker-ui` (a
|
|
1447
|
+
trigger + popover) plus a composed `<time-picker-ui>` pane — same
|
|
1448
|
+
`format`/`placement`/`open` contract, same ISO-string value shape both
|
|
1449
|
+
ways. Two near-identical implementations of the same trigger/popover/
|
|
1450
|
+
anchor/focus-trap machinery is exactly the maintenance-cost shape
|
|
1451
|
+
gh#1363 was auditing for, and `datetime-picker-ui` was still
|
|
1452
|
+
`status: experimental` with zero corpus chunks — "the cheap moment
|
|
1453
|
+
closes at stabilization." `calendar-picker-ui[precision]` also closes two
|
|
1454
|
+
sibling-contract gaps `calendar-picker-ui` had relative to its own
|
|
1455
|
+
siblings (`readonly` with real behavior, not just an inherited-but-unwired
|
|
1456
|
+
property; `name`/`min`/`max` documented `reflect: true`, matching what the
|
|
1457
|
+
class already did).
|
|
1458
|
+
|
|
1459
|
+
**Breaking removals on `calendar-picker-ui`:**
|
|
1460
|
+
|
|
1461
|
+
| Old | New |
|
|
1462
|
+
|---|---|
|
|
1463
|
+
| `<calendar-picker-ui label="…">` | `<field-ui label="…"><calendar-picker-ui></calendar-picker-ui></field-ui>` — matches every sibling picker (`date-range-picker-ui`, `datetime-picker-ui`, `time-picker-ui` never had a first-class `label`; this was `calendar-picker-ui`'s own outlier) |
|
|
1464
|
+
| `slot="label"` child on `<calendar-picker-ui>` | drop it — same rationale; the slot was never wired to any rendering either |
|
|
1465
|
+
|
|
1466
|
+
**Breaking token removals on `datetime-picker-ui`** (it owns no CSS custom
|
|
1467
|
+
properties of its own anymore — everything routes through
|
|
1468
|
+
`calendar-picker-ui`'s `--calendar-picker-*` tokens, which the two tags
|
|
1469
|
+
now share):
|
|
1470
|
+
|
|
1471
|
+
| Old token | New token |
|
|
1472
|
+
|---|---|
|
|
1473
|
+
| `--datetime-picker-popover-bg` | `--calendar-picker-popover-bg` |
|
|
1474
|
+
| `--datetime-picker-popover-border` | `--calendar-picker-popover-border` |
|
|
1475
|
+
| `--datetime-picker-popover-radius` | `--calendar-picker-popover-radius` |
|
|
1476
|
+
| `--datetime-picker-popover-shadow` | `--calendar-picker-popover-shadow` |
|
|
1477
|
+
| `--datetime-picker-popover-padding` | `--calendar-picker-popover-padding` |
|
|
1478
|
+
| `--datetime-picker-popover-gap` | `--calendar-picker-popover-gap` |
|
|
1479
|
+
| `--datetime-picker-divider` | `--calendar-picker-divider` |
|
|
1480
|
+
| `--datetime-picker-duration` | `--calendar-picker-duration` |
|
|
1481
|
+
| `--datetime-picker-easing` | `--calendar-picker-easing` |
|
|
1482
|
+
| `--datetime-picker-bg`, `--datetime-picker-fg` | *removed, no replacement* — the host paints no background of its own; text color inherits |
|
|
1483
|
+
| `--datetime-picker-trigger-min-width`, `--datetime-picker-px`, `--datetime-picker-py` | *removed, no replacement* — the trigger sizes to content; set width/padding via ordinary CSS on the host if a fixed size is wanted |
|
|
1484
|
+
|
|
1485
|
+
**Recommended migration (non-breaking, on your own schedule):**
|
|
1486
|
+
`<datetime-picker-ui name="…">` → `<calendar-picker-ui precision="minute" name="…">`
|
|
1487
|
+
(or `precision="second"` for the former second-precision mode) — every
|
|
1488
|
+
other attribute name is unchanged.
|
|
1489
|
+
|
|
1490
|
+
**Find every affected consumer site with the repo's own scanner:**
|
|
1491
|
+
|
|
1492
|
+
```bash
|
|
1493
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref> \
|
|
1494
|
+
--roots packages,apps,playgrounds,site,site-a2ui
|
|
1495
|
+
```
|
|
1496
|
+
|
|
1497
|
+
The `--roots` addition is required here — the scanner's own default roots
|
|
1498
|
+
miss `site-a2ui/` (ADR-0063's own consumer-scan note applies equally to
|
|
1499
|
+
this rider). The removed `label` prop/slot has no reported sites in this
|
|
1500
|
+
repo as of the fold landing; the `--datetime-picker-*` token findings are
|
|
1501
|
+
expected to fire on `datetime-picker.examples.html`'s own old→new
|
|
1502
|
+
reference table above (that's documentation explaining the rename, not a
|
|
1503
|
+
live override — disregard that one self-hit). `<datetime-picker-ui>` tag
|
|
1504
|
+
usage itself is a soft-deprecation candidate, not a scanner finding (the
|
|
1505
|
+
tag isn't removed):
|
|
1506
|
+
|
|
1507
|
+
```bash
|
|
1508
|
+
rg -nU '<datetime-picker-ui\b[^>]*>' \
|
|
1509
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
1510
|
+
-g '!.claude/docs/**' # any hit is a migration candidate, not a failure — the tag still works
|
|
1511
|
+
```
|
|
1512
|
+
|
|
1513
|
+
### Verify
|
|
1514
|
+
|
|
1515
|
+
```bash
|
|
1516
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref> --roots packages,apps,playgrounds,site,site-a2ui
|
|
1517
|
+
rg -nU '<calendar-picker-ui\b[^>]*\blabel=' -g '!.claude/docs/**' # must be 0
|
|
1518
|
+
npm run check
|
|
1519
|
+
```
|
|
1520
|
+
|
|
1521
|
+
---
|
|
1522
|
+
|
|
1523
|
+
<a id="upcoming--a2ui-catalog-component-collision-adminshell--uichatthread-090-gh1427"></a>
|
|
1524
|
+
## Shipped in `0.8.41` — A2UI catalog `component:` collision: `AdminShell` / `UIChatThread` (gh#1427)
|
|
1525
|
+
|
|
1526
|
+
**BREAKING for hand-authored or generated A2UI documents only — no DOM/JS API
|
|
1527
|
+
change.** `<admin-shell>` and `<chat-thread-ui>` keep their existing tag
|
|
1528
|
+
names, props, and events unchanged. What changed is the **A2UI catalog's**
|
|
1529
|
+
internal `component:` identifier — the value that appears in a rendered
|
|
1530
|
+
a2ui JSON tree's `"component"` field and the L0 catalog's own top-level key.
|
|
1531
|
+
|
|
1532
|
+
**Why:** `packages/web-modules/shell/admin-shell/admin-shell.yaml` and
|
|
1533
|
+
`packages/web-modules/shell/embed-shell/embed-shell.yaml` both declared
|
|
1534
|
+
`component: AppShell`. `scripts/build/components.mjs` used that field as the
|
|
1535
|
+
catalog's own key with no collision check — alphabetical directory
|
|
1536
|
+
traversal processed `admin-shell` first, so `embed-shell`'s fragment
|
|
1537
|
+
silently overwrote it: the L0 catalog's `components.AppShell` entry held
|
|
1538
|
+
**embed-shell's** (experimental) contract, and `admin-shell` (stable, the
|
|
1539
|
+
more heavily used shell) had **no L0 catalog schema entry at all** — no
|
|
1540
|
+
build error, no warning. Fixed by giving `admin-shell` its own catalog
|
|
1541
|
+
identity, `AdminShell`, matching the existing `registry.js` mapping
|
|
1542
|
+
(`['AdminShell', 'admin-shell']`) that had already anticipated this;
|
|
1543
|
+
`embed-shell` keeps `AppShell` (its own established, intentional mapping).
|
|
1544
|
+
`scripts/build/components.mjs` also gained a build-time collision guard — a
|
|
1545
|
+
duplicate `component:` value across yaml SoTs now throws instead of
|
|
1546
|
+
silently overwriting, which caught a second, independent instance of the
|
|
1547
|
+
identical defect: `packages/web-components/components/chat-thread/
|
|
1548
|
+
chat-thread.yaml` (the primitive, tag `chat-thread-ui`) still declared
|
|
1549
|
+
`component: ChatThread`, colliding with the chat web-module's own
|
|
1550
|
+
`ChatThread` (tag `chat-thread`, `registry.js`'s `['ChatThread',
|
|
1551
|
+
'chat-thread']` mapping). Renamed the primitive's catalog identity to
|
|
1552
|
+
`UIChatThread` (matching its own `name:` field), added the matching
|
|
1553
|
+
`registry.js` entry.
|
|
1554
|
+
|
|
1555
|
+
**Migration:**
|
|
1556
|
+
|
|
1557
|
+
| Old (a2ui JSON) | New (a2ui JSON) | HTML tag (unchanged) |
|
|
1558
|
+
|---|---|---|
|
|
1559
|
+
| `{"component": "AppShell", ...}` intending the **stable admin shell** | `{"component": "AdminShell", ...}` | `<admin-shell>` |
|
|
1560
|
+
| `{"component": "AppShell", ...}` intending the **experimental embed shell** | unchanged — still `{"component": "AppShell", ...}` | `<embed-shell>` |
|
|
1561
|
+
| `{"component": "ChatThread", ...}` intending the **primitive** scroll container (used OUTSIDE a `<chat-shell>`) | `{"component": "UIChatThread", ...}` | `<chat-thread-ui>` |
|
|
1562
|
+
| `{"component": "ChatThread", ...}` intending the **chat-shell module child** | unchanged — still `{"component": "ChatThread", ...}` | `<chat-thread>` |
|
|
1563
|
+
|
|
1564
|
+
Only a consumer that hand-authors or generates raw A2UI trees referencing
|
|
1565
|
+
these `component` values directly is affected — component authoring via
|
|
1566
|
+
the HTML tags themselves (`<admin-shell>`, `<chat-thread-ui>`) needs no
|
|
1567
|
+
change. Any pre-fix generation that produced `"component": "AppShell"`
|
|
1568
|
+
meaning admin-shell was already silently wrong (it validated against
|
|
1569
|
+
embed-shell's schema instead) — this migration corrects, not breaks, that
|
|
1570
|
+
path.
|
|
1571
|
+
|
|
1572
|
+
### Verify
|
|
1573
|
+
|
|
1574
|
+
```bash
|
|
1575
|
+
rg -nU '"component"\s*:\s*"(AppShell|ChatThread)"' \
|
|
1576
|
+
-g '!**/dist/**' -g '!*MIGRATION*' -g '!.claude/docs/**' -g '!**/corpus/chunks/**'
|
|
1577
|
+
npm run check
|
|
1578
|
+
```
|
|
1579
|
+
|
|
1580
|
+
---
|
|
1581
|
+
|
|
1582
|
+
<a id="upcoming--progress-row-ui-deprecated--absorbed-into-progress-ui-090-gh1373"></a>
|
|
1583
|
+
## Shipped in `0.8.41` — `progress-row-ui` deprecated — absorbed into `progress-ui` (gh#1373)
|
|
1584
|
+
|
|
1585
|
+
**Non-breaking, deprecation alias.** `<progress-ui>` gains a `label` +
|
|
1586
|
+
`meta` prop pair. A non-empty `label` switches `<progress-ui>` into the
|
|
1587
|
+
same labeled-row layout `<progress-row-ui>` renders — label + bar +
|
|
1588
|
+
optional right-aligned `meta` text — a new Sanctioned Mode Attribute
|
|
1589
|
+
(`.claude/docs/specs/component-token-contract.md`'s Modes table).
|
|
1590
|
+
`<progress-row-ui>` itself is unchanged at the implementation level
|
|
1591
|
+
(still composes `<progress-ui>` internally, exact same runtime
|
|
1592
|
+
behavior) but ships `status: deprecated` (ADR-0057's vocabulary) — the
|
|
1593
|
+
site badges it, and the A2UI catalog no longer teaches or generates it.
|
|
1594
|
+
|
|
1595
|
+
**Why:** filed from the catalog-regularity audit's C4 finding
|
|
1596
|
+
([gh#1363](https://github.com/adiahealth/gen-ui-kit/issues/1363)) —
|
|
1597
|
+
`progress-row.yaml:10-15` is a thin label+meta wrapper over
|
|
1598
|
+
`progress-ui`, and the catalog already believed they were one
|
|
1599
|
+
component: `progress.yaml`'s own canonical `dashboard` example put
|
|
1600
|
+
`label` on a `Progress` node — a prop only `ProgressRow` had — meaning
|
|
1601
|
+
generation copying the catalog's own exemplar failed validation before
|
|
1602
|
+
this rider.
|
|
1603
|
+
|
|
1604
|
+
**Migration:**
|
|
1605
|
+
|
|
1606
|
+
| Old | New |
|
|
1607
|
+
|---|---|
|
|
1608
|
+
| `<progress-row-ui label="…" value="…" meta="…">` | `<progress-ui label="…" value="…" meta="…">` — attribute names unchanged, a mechanical tag rename |
|
|
1609
|
+
| `<progress-row-ui label="…">` (no meta) | `<progress-ui label="…">` |
|
|
1610
|
+
| `<progress-row-ui variant="success\|warning\|danger">` | **no successor** — see below |
|
|
1611
|
+
| `<progress-row-ui>` (unmodified) | keeps working; not required to migrate, but no longer the taught/generated shape |
|
|
1612
|
+
|
|
1613
|
+
**`variant` (the row's color-family prop) has no successor on
|
|
1614
|
+
`<progress-ui>`.** Progress's own `variant` prop was already retired
|
|
1615
|
+
bar-only in the C2 rider ([gh#1370](https://github.com/adiahealth/gen-ui-kit/issues/1370))
|
|
1616
|
+
and stays retired — this rider does not reopen it, since none of the
|
|
1617
|
+
repo's own authored consumers used `progress-row-ui[variant]` (a
|
|
1618
|
+
`qa:contract-migration-scan` + `rg` sweep of every real usage site
|
|
1619
|
+
found zero). To recolor the fill in row layout, override the
|
|
1620
|
+
`--progress-fill` token directly — `--progress-fill:
|
|
1621
|
+
var(--a-success-bg)`, `--progress-fill: var(--a-warning-bg)`, or
|
|
1622
|
+
`--progress-fill: var(--a-danger-bg)` — the same token-only convention
|
|
1623
|
+
progress's yaml has documented since before this change ("there is no
|
|
1624
|
+
variant-as-color, use the token").
|
|
1625
|
+
|
|
1626
|
+
**Find every affected consumer site:**
|
|
1627
|
+
|
|
1628
|
+
```bash
|
|
1629
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1630
|
+
rg -nU '<progress-row-ui[^>]*>' \
|
|
1631
|
+
-g '!*CHANGELOG*.md' -g '!**/dist/**' -g '!*.examples.md' -g '!*MIGRATION*' \
|
|
1632
|
+
-g '!.claude/docs/**'
|
|
1633
|
+
```
|
|
1634
|
+
|
|
1635
|
+
The scanner's diff detection is scoped to a yaml losing a `props`/
|
|
1636
|
+
`tokens` key or its `tag:` field (its own documented v1 scope) — this
|
|
1637
|
+
change is additive on `progress.yaml` and non-breaking on
|
|
1638
|
+
`progress-row.yaml`, so expect it to report no contract break; the
|
|
1639
|
+
`rg` sweep is the one that finds real markup sites to migrate (not
|
|
1640
|
+
required — `progress-row-ui` keeps working — but recommended so new
|
|
1641
|
+
edits to a touched file land on the current shape).
|
|
1642
|
+
|
|
1643
|
+
### Verify
|
|
1644
|
+
|
|
1645
|
+
```bash
|
|
1646
|
+
npm run qa:contract-migration-scan -- --base <pre-upgrade-ref> --head <post-upgrade-ref>
|
|
1647
|
+
npm run harvest:chunks # re-validates every chunk against the updated catalog
|
|
1648
|
+
npm run check
|
|
1649
|
+
```
|
|
1650
|
+
|
|
1651
|
+
---
|
|
1652
|
+
|
|
387
1653
|
## Migrating to `@adia-ai/*@v0.8.23` (2026-07-30)
|
|
388
1654
|
|
|
389
1655
|
- **Removed: the `--a-font` alias** (pre-ADR-0035 name, DEPRECATED since the 0.8.x line). Any surviving `font-family: var(--a-font)` goes invalid-at-computed-value-time → `inherit` → UA **serif** — the visible symptom is Times-faced labels on an otherwise-correct page.
|