@adia-ai/web-components 0.6.33 → 0.6.35
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 +64 -0
- package/color/index.js +1 -1
- package/components/accordion/accordion-item.yaml +2 -2
- package/components/accordion/accordion.css +2 -2
- package/components/accordion/accordion.js +1 -1
- package/components/action-list/action-item.yaml +2 -2
- package/components/action-list/action-list.css +2 -2
- package/components/action-list/action-list.js +1 -1
- package/components/agent-artifact/{class.js → agent-artifact.class.js} +1 -1
- package/components/agent-artifact/agent-artifact.css +31 -31
- package/components/agent-artifact/agent-artifact.js +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.css +10 -10
- package/components/agent-feedback-bar/agent-feedback-bar.js +1 -1
- package/components/agent-questions/agent-questions.css +57 -57
- package/components/agent-questions/agent-questions.js +1 -1
- package/components/agent-reasoning/agent-reasoning.css +62 -62
- package/components/agent-reasoning/agent-reasoning.js +1 -1
- package/components/agent-suggestions/agent-suggestions.css +4 -4
- package/components/agent-suggestions/agent-suggestions.js +1 -1
- package/components/agent-trace/agent-trace.css +53 -53
- package/components/alert/alert.a2ui.json +64 -1
- package/components/alert/{class.js → alert.class.js} +189 -2
- package/components/alert/alert.css +119 -41
- package/components/alert/alert.d.ts +14 -0
- package/components/alert/alert.js +1 -1
- package/components/alert/alert.test.js +184 -0
- package/components/alert/alert.yaml +114 -1
- package/components/avatar/avatar-group.yaml +2 -2
- package/components/avatar/avatar.css +27 -27
- package/components/avatar/avatar.js +1 -1
- package/components/badge/badge.css +27 -27
- package/components/badge/badge.js +1 -1
- package/components/block/block.css +16 -16
- package/components/block/block.js +1 -1
- package/components/breadcrumb/breadcrumb.css +23 -23
- package/components/breadcrumb/breadcrumb.js +1 -1
- package/components/button/button.css +101 -91
- package/components/button/button.js +1 -1
- package/components/calendar-grid/calendar-grid.a2ui.json +146 -0
- package/components/calendar-grid/calendar-grid.class.js +326 -0
- package/components/calendar-grid/calendar-grid.css +246 -0
- package/components/calendar-grid/calendar-grid.d.ts +41 -0
- package/components/calendar-grid/calendar-grid.js +17 -0
- package/components/calendar-grid/calendar-grid.yaml +136 -0
- package/components/calendar-picker/calendar-picker.css +139 -139
- package/components/calendar-picker/calendar-picker.js +1 -1
- package/components/canvas/canvas.css +12 -12
- package/components/card/card.css +83 -83
- package/components/card/card.js +1 -1
- package/components/chart/chart.css +224 -224
- package/components/chart/chart.js +1 -1
- package/components/chart-legend/chart-legend.css +26 -26
- package/components/chart-legend/chart-legend.js +1 -1
- package/components/chat-thread/chat-input.a2ui.json +1 -1
- package/components/chat-thread/chat-input.js +6 -1
- package/components/chat-thread/chat-input.yaml +4 -1
- package/components/chat-thread/chat-thread.js +1 -1
- package/components/check/check.css +40 -40
- package/components/check/check.js +1 -1
- package/components/code/code.css +125 -125
- package/components/code/code.js +1 -1
- package/components/col/col.css +15 -15
- package/components/col/col.js +1 -1
- package/components/color-input/color-input.js +1 -1
- package/components/color-picker/color-picker.css +55 -55
- package/components/color-picker/color-picker.js +1 -1
- package/components/combobox/combobox.a2ui.json +363 -0
- package/components/combobox/combobox.class.js +861 -0
- package/components/combobox/combobox.css +244 -0
- package/components/combobox/combobox.d.ts +113 -0
- package/components/combobox/combobox.examples.md +59 -0
- package/components/combobox/combobox.js +17 -0
- package/components/combobox/combobox.test.js +181 -0
- package/components/combobox/combobox.yaml +369 -0
- package/components/command/command.css +90 -90
- package/components/command/command.js +1 -1
- package/components/date-range-picker/date-range-picker.a2ui.json +300 -0
- package/components/date-range-picker/date-range-picker.class.js +791 -0
- package/components/date-range-picker/date-range-picker.css +224 -0
- package/components/date-range-picker/date-range-picker.d.ts +82 -0
- package/components/date-range-picker/date-range-picker.examples.md +37 -0
- package/components/date-range-picker/date-range-picker.js +17 -0
- package/components/date-range-picker/date-range-picker.test.js +387 -0
- package/components/date-range-picker/date-range-picker.yaml +285 -0
- package/components/datetime-picker/datetime-picker.a2ui.json +334 -0
- package/components/datetime-picker/datetime-picker.class.js +706 -0
- package/components/datetime-picker/datetime-picker.css +150 -0
- package/components/datetime-picker/datetime-picker.d.ts +86 -0
- package/components/datetime-picker/datetime-picker.examples.md +46 -0
- package/components/datetime-picker/datetime-picker.js +17 -0
- package/components/datetime-picker/datetime-picker.test.js +454 -0
- package/components/datetime-picker/datetime-picker.yaml +332 -0
- package/components/demo-toggle/demo-toggle.css +27 -27
- package/components/demo-toggle/demo-toggle.js +1 -1
- package/components/description-list/description-list.css +18 -18
- package/components/description-list/description-list.js +1 -1
- package/components/divider/divider.css +24 -24
- package/components/divider/divider.js +1 -1
- package/components/drawer/drawer.js +1 -1
- package/components/embed/embed.css +6 -6
- package/components/embed/embed.js +1 -1
- package/components/empty-state/empty-state.css +27 -27
- package/components/empty-state/empty-state.js +1 -1
- package/components/feed/feed.css +12 -12
- package/components/feed/feed.js +1 -1
- package/components/field/field.css +28 -28
- package/components/field/field.js +1 -1
- package/components/field/field.test.js +1 -1
- package/components/fields/fields.css +5 -5
- package/components/fields/fields.js +1 -1
- package/components/grid/grid.css +5 -5
- package/components/grid/grid.js +1 -1
- package/components/heatmap/heatmap.css +63 -63
- package/components/heatmap/heatmap.js +1 -1
- package/components/icon/icon.css +12 -12
- package/components/icon/icon.js +1 -1
- package/components/image/image.css +14 -14
- package/components/image/image.js +1 -1
- package/components/index.js +11 -0
- package/components/inline-message/inline-message.a2ui.json +143 -0
- package/components/inline-message/inline-message.class.js +169 -0
- package/components/inline-message/inline-message.css +75 -0
- package/components/inline-message/inline-message.d.ts +31 -0
- package/components/inline-message/inline-message.examples.md +19 -0
- package/components/inline-message/inline-message.js +17 -0
- package/components/inline-message/inline-message.test.js +203 -0
- package/components/inline-message/inline-message.yaml +205 -0
- package/components/input/input.css +67 -67
- package/components/input/input.js +1 -1
- package/components/input/input.yaml +5 -4
- package/components/inspector/inspector.css +6 -6
- package/components/inspector/inspector.js +1 -1
- package/components/integration-card/integration-card.a2ui.json +268 -0
- package/components/integration-card/integration-card.class.js +410 -0
- package/components/integration-card/integration-card.css +169 -0
- package/components/integration-card/integration-card.d.ts +63 -0
- package/components/integration-card/integration-card.examples.md +41 -0
- package/components/integration-card/integration-card.js +17 -0
- package/components/integration-card/integration-card.test.js +306 -0
- package/components/integration-card/integration-card.yaml +280 -0
- package/components/kbd/kbd.css +32 -32
- package/components/kbd/kbd.js +1 -1
- package/components/link/link.css +12 -12
- package/components/link/link.js +1 -1
- package/components/list/list-item.yaml +2 -2
- package/components/list/list.css +8 -8
- package/components/list/list.js +1 -1
- package/components/list-window/list-window.a2ui.json +277 -0
- package/components/list-window/list-window.class.js +688 -0
- package/components/list-window/list-window.css +124 -0
- package/components/list-window/list-window.d.ts +84 -0
- package/components/list-window/list-window.examples.md +73 -0
- package/components/list-window/list-window.js +17 -0
- package/components/list-window/list-window.test.js +303 -0
- package/components/list-window/list-window.yaml +270 -0
- package/components/loading-overlay/loading-overlay.a2ui.json +176 -0
- package/components/loading-overlay/loading-overlay.class.js +203 -0
- package/components/loading-overlay/loading-overlay.css +81 -0
- package/components/loading-overlay/loading-overlay.d.ts +24 -0
- package/components/loading-overlay/loading-overlay.examples.md +50 -0
- package/components/loading-overlay/loading-overlay.js +17 -0
- package/components/loading-overlay/loading-overlay.test.js +257 -0
- package/components/loading-overlay/loading-overlay.yaml +260 -0
- package/components/menu/menu-divider.yaml +1 -1
- package/components/menu/menu-item.yaml +1 -1
- package/components/menu/menu.a2ui.json +3 -0
- package/components/menu/menu.css +8 -8
- package/components/menu/menu.js +1 -1
- package/components/menu/menu.yaml +7 -0
- package/components/modal/{class.js → modal.class.js} +12 -1
- package/components/modal/modal.css +54 -44
- package/components/modal/modal.js +1 -1
- package/components/nav/nav.css +40 -40
- package/components/nav/nav.js +1 -1
- package/components/nav-group/nav-group.css +52 -52
- package/components/nav-group/nav-group.js +1 -1
- package/components/nav-item/nav-item.css +44 -44
- package/components/nav-item/nav-item.js +1 -1
- package/components/noodles/noodles.css +31 -31
- package/components/noodles/noodles.js +1 -1
- package/components/option-card/option-card.css +69 -69
- package/components/option-card/option-card.js +1 -1
- package/components/otp-input/otp-input.css +30 -30
- package/components/otp-input/otp-input.js +1 -1
- package/components/page/page.css +18 -18
- package/components/page/page.js +1 -1
- package/components/pagination/pagination.css +61 -61
- package/components/pagination/pagination.js +1 -1
- package/components/pane/pane.css +57 -57
- package/components/pane/pane.js +1 -1
- package/components/pipeline-status/pipeline-status.css +65 -65
- package/components/pipeline-status/pipeline-status.js +1 -1
- package/components/popover/popover.a2ui.json +8 -1
- package/components/popover/popover.css +17 -17
- package/components/popover/popover.js +1 -1
- package/components/popover/popover.yaml +14 -1
- package/components/progress/progress.css +23 -23
- package/components/progress/progress.js +1 -1
- package/components/progress-row/progress-row.css +17 -17
- package/components/progress-row/progress-row.js +1 -1
- package/components/radio/radio.css +39 -39
- package/components/radio/radio.js +1 -1
- package/components/range/range.css +55 -55
- package/components/range/range.js +1 -1
- package/components/rating/rating.css +28 -28
- package/components/rating/rating.js +1 -1
- package/components/richtext/richtext.css +133 -133
- package/components/richtext/richtext.js +1 -1
- package/components/row/row.css +19 -19
- package/components/row/row.js +1 -1
- package/components/search/search.css +5 -5
- package/components/search/search.js +1 -1
- package/components/segment/segment.css +24 -24
- package/components/segment/segment.js +1 -1
- package/components/segmented/segmented.css +25 -25
- package/components/segmented/segmented.js +1 -1
- package/components/select/select.a2ui.json +58 -4
- package/components/select/{class.js → select.class.js} +415 -6
- package/components/select/select.css +242 -84
- package/components/select/select.d.ts +31 -1
- package/components/select/select.js +1 -1
- package/components/select/select.test.js +202 -0
- package/components/select/select.yaml +126 -5
- package/components/skeleton/skeleton.css +14 -14
- package/components/skeleton/skeleton.js +1 -1
- package/components/slider/slider.css +46 -46
- package/components/slider/slider.js +1 -1
- package/components/spinner/spinner.a2ui.json +198 -0
- package/components/spinner/spinner.class.js +99 -0
- package/components/spinner/spinner.css +221 -0
- package/components/spinner/spinner.d.ts +26 -0
- package/components/spinner/spinner.examples.md +26 -0
- package/components/spinner/spinner.js +17 -0
- package/components/spinner/spinner.test.js +272 -0
- package/components/spinner/spinner.yaml +238 -0
- package/components/stack/stack.css +11 -11
- package/components/stack/stack.js +1 -1
- package/components/stat/stat.css +25 -25
- package/components/step-progress/step-progress.css +20 -20
- package/components/step-progress/step-progress.js +1 -1
- package/components/stepper/stepper-item.yaml +1 -1
- package/components/stepper/stepper.css +29 -29
- package/components/stepper/stepper.js +1 -1
- package/components/stream/stream.css +12 -12
- package/components/stream/stream.js +1 -1
- package/components/swatch/swatch.css +68 -68
- package/components/swatch/swatch.js +1 -1
- package/components/swiper/swiper.css +57 -57
- package/components/swiper/swiper.js +1 -1
- package/components/switch/switch.css +52 -52
- package/components/switch/switch.js +1 -1
- package/components/table/table.css +163 -163
- package/components/table/table.js +1 -1
- package/components/table-toolbar/{class.js → table-toolbar.class.js} +1 -1
- package/components/table-toolbar/table-toolbar.css +32 -32
- package/components/table-toolbar/table-toolbar.js +1 -1
- package/components/tabs/tab.yaml +2 -2
- package/components/tabs/tabs.css +51 -51
- package/components/tabs/tabs.js +1 -1
- package/components/tag/tag.css +48 -48
- package/components/tag/tag.js +1 -1
- package/components/tags-input/tags-input.a2ui.json +337 -0
- package/components/tags-input/tags-input.class.js +776 -0
- package/components/tags-input/tags-input.css +201 -0
- package/components/tags-input/tags-input.d.ts +120 -0
- package/components/tags-input/tags-input.examples.md +92 -0
- package/components/tags-input/tags-input.js +17 -0
- package/components/tags-input/tags-input.test.js +368 -0
- package/components/tags-input/tags-input.yaml +367 -0
- package/components/text/text.css +44 -44
- package/components/text/text.js +1 -1
- package/components/textarea/textarea.a2ui.json +1 -1
- package/components/textarea/textarea.css +46 -46
- package/components/textarea/textarea.js +1 -1
- package/components/textarea/textarea.yaml +11 -8
- package/components/time-picker/time-picker.a2ui.json +267 -0
- package/components/time-picker/time-picker.class.js +693 -0
- package/components/time-picker/time-picker.css +122 -0
- package/components/time-picker/time-picker.d.ts +75 -0
- package/components/time-picker/time-picker.examples.md +35 -0
- package/components/time-picker/time-picker.js +17 -0
- package/components/time-picker/time-picker.test.js +287 -0
- package/components/time-picker/time-picker.yaml +256 -0
- package/components/timeline/timeline-item.yaml +2 -2
- package/components/timeline/{class.js → timeline.class.js} +1 -1
- package/components/timeline/timeline.css +50 -50
- package/components/timeline/timeline.js +1 -1
- package/components/toast/toast.css +58 -58
- package/components/toast/toast.js +1 -1
- package/components/toggle-group/toggle-group.css +6 -6
- package/components/toggle-group/toggle-group.js +1 -1
- package/components/toggle-group/toggle-option.yaml +1 -1
- package/components/toggle-scheme/toggle-scheme.css +2 -2
- package/components/toggle-scheme/toggle-scheme.js +1 -1
- package/components/toolbar/toolbar-group.yaml +1 -1
- package/components/toolbar/toolbar.css +17 -17
- package/components/toolbar/toolbar.js +1 -1
- package/components/tooltip/tooltip.css +2 -2
- package/components/tooltip/tooltip.js +1 -1
- package/components/tree/tree-item.yaml +1 -1
- package/components/tree/tree.css +37 -37
- package/components/tree/tree.js +1 -1
- package/components/upload/upload.css +49 -49
- package/components/upload/upload.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +146 -87
- package/package.json +3 -3
- package/styles/components.css +11 -0
- /package/components/accordion/{class.js → accordion.class.js} +0 -0
- /package/components/action-list/{class.js → action-list.class.js} +0 -0
- /package/components/agent-feedback-bar/{class.js → agent-feedback-bar.class.js} +0 -0
- /package/components/agent-questions/{class.js → agent-questions.class.js} +0 -0
- /package/components/agent-reasoning/{class.js → agent-reasoning.class.js} +0 -0
- /package/components/agent-suggestions/{class.js → agent-suggestions.class.js} +0 -0
- /package/components/avatar/{class.js → avatar.class.js} +0 -0
- /package/components/badge/{class.js → badge.class.js} +0 -0
- /package/components/block/{class.js → block.class.js} +0 -0
- /package/components/breadcrumb/{class.js → breadcrumb.class.js} +0 -0
- /package/components/button/{class.js → button.class.js} +0 -0
- /package/components/calendar-picker/{class.js → calendar-picker.class.js} +0 -0
- /package/components/card/{class.js → card.class.js} +0 -0
- /package/components/chart/{class.js → chart.class.js} +0 -0
- /package/components/chart-legend/{class.js → chart-legend.class.js} +0 -0
- /package/components/chat-thread/{class.js → chat-thread.class.js} +0 -0
- /package/components/check/{class.js → check.class.js} +0 -0
- /package/components/code/{class.js → code.class.js} +0 -0
- /package/components/col/{class.js → col.class.js} +0 -0
- /package/components/color-input/{class.js → color-input.class.js} +0 -0
- /package/components/color-picker/{class.js → color-picker.class.js} +0 -0
- /package/components/command/{class.js → command.class.js} +0 -0
- /package/components/demo-toggle/{class.js → demo-toggle.class.js} +0 -0
- /package/components/description-list/{class.js → description-list.class.js} +0 -0
- /package/components/divider/{class.js → divider.class.js} +0 -0
- /package/components/drawer/{class.js → drawer.class.js} +0 -0
- /package/components/embed/{class.js → embed.class.js} +0 -0
- /package/components/empty-state/{class.js → empty-state.class.js} +0 -0
- /package/components/feed/{class.js → feed.class.js} +0 -0
- /package/components/field/{class.js → field.class.js} +0 -0
- /package/components/fields/{class.js → fields.class.js} +0 -0
- /package/components/grid/{class.js → grid.class.js} +0 -0
- /package/components/heatmap/{class.js → heatmap.class.js} +0 -0
- /package/components/icon/{class.js → icon.class.js} +0 -0
- /package/components/image/{class.js → image.class.js} +0 -0
- /package/components/input/{class.js → input.class.js} +0 -0
- /package/components/inspector/{class.js → inspector.class.js} +0 -0
- /package/components/kbd/{class.js → kbd.class.js} +0 -0
- /package/components/link/{class.js → link.class.js} +0 -0
- /package/components/list/{class.js → list.class.js} +0 -0
- /package/components/menu/{class.js → menu.class.js} +0 -0
- /package/components/nav/{class.js → nav.class.js} +0 -0
- /package/components/nav-group/{class.js → nav-group.class.js} +0 -0
- /package/components/nav-item/{class.js → nav-item.class.js} +0 -0
- /package/components/noodles/{class.js → noodles.class.js} +0 -0
- /package/components/option-card/{class.js → option-card.class.js} +0 -0
- /package/components/otp-input/{class.js → otp-input.class.js} +0 -0
- /package/components/page/{class.js → page.class.js} +0 -0
- /package/components/pagination/{class.js → pagination.class.js} +0 -0
- /package/components/pane/{class.js → pane.class.js} +0 -0
- /package/components/pipeline-status/{class.js → pipeline-status.class.js} +0 -0
- /package/components/popover/{class.js → popover.class.js} +0 -0
- /package/components/progress/{class.js → progress.class.js} +0 -0
- /package/components/progress-row/{class.js → progress-row.class.js} +0 -0
- /package/components/radio/{class.js → radio.class.js} +0 -0
- /package/components/range/{class.js → range.class.js} +0 -0
- /package/components/rating/{class.js → rating.class.js} +0 -0
- /package/components/richtext/{class.js → richtext.class.js} +0 -0
- /package/components/row/{class.js → row.class.js} +0 -0
- /package/components/search/{class.js → search.class.js} +0 -0
- /package/components/segment/{class.js → segment.class.js} +0 -0
- /package/components/segmented/{class.js → segmented.class.js} +0 -0
- /package/components/skeleton/{class.js → skeleton.class.js} +0 -0
- /package/components/slider/{class.js → slider.class.js} +0 -0
- /package/components/stack/{class.js → stack.class.js} +0 -0
- /package/components/step-progress/{class.js → step-progress.class.js} +0 -0
- /package/components/stepper/{class.js → stepper.class.js} +0 -0
- /package/components/stream/{class.js → stream.class.js} +0 -0
- /package/components/swatch/{class.js → swatch.class.js} +0 -0
- /package/components/swiper/{class.js → swiper.class.js} +0 -0
- /package/components/switch/{class.js → switch.class.js} +0 -0
- /package/components/table/{class.js → table.class.js} +0 -0
- /package/components/tabs/{class.js → tabs.class.js} +0 -0
- /package/components/tag/{class.js → tag.class.js} +0 -0
- /package/components/text/{class.js → text.class.js} +0 -0
- /package/components/textarea/{class.js → textarea.class.js} +0 -0
- /package/components/toast/{class.js → toast.class.js} +0 -0
- /package/components/toggle-group/{class.js → toggle-group.class.js} +0 -0
- /package/components/toggle-scheme/{class.js → toggle-scheme.class.js} +0 -0
- /package/components/toolbar/{class.js → toolbar.class.js} +0 -0
- /package/components/tooltip/{class.js → tooltip.class.js} +0 -0
- /package/components/tree/{class.js → tree.class.js} +0 -0
- /package/components/upload/{class.js → upload.class.js} +0 -0
|
@@ -23,6 +23,16 @@
|
|
|
23
23
|
"type": "string",
|
|
24
24
|
"default": ""
|
|
25
25
|
},
|
|
26
|
+
"amount": {
|
|
27
|
+
"description": "Dunning mode only — the unpaid amount as a decimal major-unit number (`24.50`, not minor units like `2450`). Formatted via `Intl.NumberFormat` using [currency] and [lang]. Ignored when [pattern] is not `dunning`.",
|
|
28
|
+
"type": "number",
|
|
29
|
+
"default": 0
|
|
30
|
+
},
|
|
31
|
+
"cardLast4": {
|
|
32
|
+
"description": "Dunning mode only — last 4 digits of the declined card. Rendered as \"ending 4242\". Ignored when [pattern] is not `dunning`. Attribute spelling: `card-last4`.",
|
|
33
|
+
"type": "string",
|
|
34
|
+
"default": ""
|
|
35
|
+
},
|
|
26
36
|
"closable": {
|
|
27
37
|
"description": "Whether a close button is displayed. Alias [dismissible] is also accepted (same semantics, different spelling — the corpus and many libraries use both; both map to the same state).",
|
|
28
38
|
"type": "boolean",
|
|
@@ -31,16 +41,47 @@
|
|
|
31
41
|
"component": {
|
|
32
42
|
"const": "Alert"
|
|
33
43
|
},
|
|
44
|
+
"currency": {
|
|
45
|
+
"description": "Dunning mode only — ISO 4217 currency code driving the `Intl.NumberFormat` style=\"currency\" rendering. Defaults to `USD`.",
|
|
46
|
+
"type": "string",
|
|
47
|
+
"default": "USD"
|
|
48
|
+
},
|
|
34
49
|
"dismissible": {
|
|
35
50
|
"description": "Public alias for [closable] — same semantics. Both attributes render the close button. Use whichever spelling matches your authoring style.",
|
|
36
51
|
"type": "boolean",
|
|
37
52
|
"default": false
|
|
38
53
|
},
|
|
54
|
+
"dueAt": {
|
|
55
|
+
"description": "Dunning mode only — ISO 8601 due / failed-at timestamp. Formatted via `Intl.DateTimeFormat`. Ignored when [pattern] is not `dunning`. Attribute spelling: `due-at`.",
|
|
56
|
+
"type": "string",
|
|
57
|
+
"default": ""
|
|
58
|
+
},
|
|
39
59
|
"icon": {
|
|
40
60
|
"description": "Icon identifier displayed before the message content",
|
|
41
61
|
"type": "string",
|
|
42
62
|
"default": ""
|
|
43
63
|
},
|
|
64
|
+
"pattern": {
|
|
65
|
+
"description": "Domain pattern mode. Default is empty (standard alert). Setting `pattern=\"dunning\"` switches to billing dunning render mode — stamps a formatted amount + due-date + decline-reason from props and re-dispatches descendant `[data-dunning-action]` button clicks as a unified `dunning-action` event. Spec: SPEC-006.",
|
|
66
|
+
"type": "string",
|
|
67
|
+
"enum": [
|
|
68
|
+
"",
|
|
69
|
+
"dunning"
|
|
70
|
+
],
|
|
71
|
+
"default": ""
|
|
72
|
+
},
|
|
73
|
+
"reason": {
|
|
74
|
+
"description": "Dunning mode only — decline reason. Drives the leading icon (declined → `x-circle`, expired → `clock`, insufficient → `wallet`, network → `wifi-slash`). One of: `declined`, `expired`, `insufficient`, `network`, or empty.",
|
|
75
|
+
"type": "string",
|
|
76
|
+
"enum": [
|
|
77
|
+
"",
|
|
78
|
+
"declined",
|
|
79
|
+
"expired",
|
|
80
|
+
"insufficient",
|
|
81
|
+
"network"
|
|
82
|
+
],
|
|
83
|
+
"default": ""
|
|
84
|
+
},
|
|
44
85
|
"text": {
|
|
45
86
|
"description": "Single-line alert message. For two-line \"headline + body\" alerts, use [title] + [description] instead. For rich content (links, formatting), use the [slot=\"content\"] slot.",
|
|
46
87
|
"type": "string",
|
|
@@ -66,12 +107,26 @@
|
|
|
66
107
|
],
|
|
67
108
|
"unevaluatedProperties": false,
|
|
68
109
|
"x-adiaui": {
|
|
69
|
-
"anti_patterns": [
|
|
110
|
+
"anti_patterns": [
|
|
111
|
+
{
|
|
112
|
+
"fix": "<alert-ui pattern=\"dunning\" variant=\"danger\">",
|
|
113
|
+
"why": "Dunning is always a failure surface; info mis-signals severity.",
|
|
114
|
+
"wrong": "<alert-ui pattern=\"dunning\" variant=\"info\">"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"fix": "<alert-ui pattern=\"dunning\" amount=\"24.50\" currency=\"USD\" due-at=\"2026-05-20\">",
|
|
118
|
+
"why": "Amount baked into title defeats Intl formatting + telemetry.",
|
|
119
|
+
"wrong": "<alert-ui pattern=\"dunning\" title=\"Payment failed $24.50\">"
|
|
120
|
+
}
|
|
121
|
+
],
|
|
70
122
|
"category": "container",
|
|
71
123
|
"composes": [],
|
|
72
124
|
"events": {
|
|
73
125
|
"close": {
|
|
74
126
|
"description": "Fired when the close button is clicked"
|
|
127
|
+
},
|
|
128
|
+
"dunning-action": {
|
|
129
|
+
"description": "Dunning pattern only — fired when a descendant button with `[data-dunning-action]` is clicked. Detail shape `{ action, amount, currency, dueAt }`; the action string is the value of the `data-dunning-action` attribute (typically `\"update\"` or `\"retry\"`)."
|
|
75
130
|
}
|
|
76
131
|
},
|
|
77
132
|
"examples": [
|
|
@@ -84,6 +139,11 @@
|
|
|
84
139
|
"description": "Card with error alert and a retry button for error state display.",
|
|
85
140
|
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Card\",\n \"children\": [\n \"sec\",\n \"ftr\"\n ]\n },\n {\n \"id\": \"sec\",\n \"component\": \"Section\",\n \"children\": [\n \"alert\"\n ]\n },\n {\n \"id\": \"alert\",\n \"component\": \"Alert\",\n \"variant\": \"error\",\n \"title\": \"Something went wrong\",\n \"description\": \"We encountered an error while loading the data. Please try again.\"\n },\n {\n \"id\": \"ftr\",\n \"component\": \"Footer\",\n \"children\": [\n \"retry\"\n ]\n },\n {\n \"id\": \"retry\",\n \"component\": \"Button\",\n \"text\": \"Retry\",\n \"icon\": \"refresh\",\n \"variant\": \"primary\"\n }\n]",
|
|
86
141
|
"name": "error-state"
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
"description": "Billing dunning banner — declined card with retry + update-card actions (SPEC-006).",
|
|
145
|
+
"a2ui": "[\n {\n \"id\": \"root\",\n \"component\": \"Alert\",\n \"pattern\": \"dunning\",\n \"variant\": \"danger\",\n \"amount\": 24.5,\n \"currency\": \"USD\",\n \"dueAt\": \"2026-05-20T00:00:00Z\",\n \"cardLast4\": \"4242\",\n \"reason\": \"declined\",\n \"children\": [\"btn-update\", \"btn-retry\"]\n },\n {\n \"id\": \"btn-update\",\n \"component\": \"Button\",\n \"text\": \"Update payment method\",\n \"variant\": \"primary\",\n \"slot\": \"actions\"\n },\n {\n \"id\": \"btn-retry\",\n \"component\": \"Button\",\n \"text\": \"Retry charge\",\n \"variant\": \"outline\",\n \"slot\": \"actions\"\n }\n]",
|
|
146
|
+
"name": "dunning-payment-failed"
|
|
87
147
|
}
|
|
88
148
|
],
|
|
89
149
|
"keywords": [
|
|
@@ -112,6 +172,9 @@
|
|
|
112
172
|
"action": {
|
|
113
173
|
"description": "Optional trailing action button (e.g. \"Refresh\", \"Status page\"). Right-aligned in the flex layout. See system-banners pattern for examples."
|
|
114
174
|
},
|
|
175
|
+
"actions": {
|
|
176
|
+
"description": "Dunning pattern only — action button stack (typically two `<button-ui>` with `data-dunning-action=\"update\"` and `data-dunning-action=\"retry\"`). Sits below the formatted message in the col layout when `pattern=\"dunning\"`."
|
|
177
|
+
},
|
|
115
178
|
"close": {
|
|
116
179
|
"description": "Close button. Stamped automatically when `closable` is set; the stamped element is `<button-ui slot=\"close\" icon=\"x\" variant=\"ghost\" size=\"sm\">`. Override by passing a custom `slot=\"close\"` button."
|
|
117
180
|
},
|
|
@@ -50,6 +50,17 @@ export class UIAlert extends UIElement {
|
|
|
50
50
|
closable: { type: Boolean, default: false, reflect: true },
|
|
51
51
|
dismissible: { type: Boolean, default: false, reflect: true },
|
|
52
52
|
icon: { type: String, default: '', reflect: true },
|
|
53
|
+
/* SPEC-006 dunning pattern \u2014 billing payment-failed mode. When
|
|
54
|
+
`pattern="dunning"`, the alert stamps an Intl-formatted amount +
|
|
55
|
+
due-date + decline-reason from the props below and re-dispatches
|
|
56
|
+
descendant `[data-dunning-action]` button clicks as a unified
|
|
57
|
+
`dunning-action` event. See SPEC-006 for the full rationale. */
|
|
58
|
+
pattern: { type: String, default: '', reflect: true },
|
|
59
|
+
amount: { type: Number, default: 0, reflect: true },
|
|
60
|
+
currency: { type: String, default: 'USD', reflect: true },
|
|
61
|
+
dueAt: { type: String, default: '', reflect: true, attribute: 'due-at' },
|
|
62
|
+
cardLast4: { type: String, default: '', reflect: true, attribute: 'card-last4' },
|
|
63
|
+
reason: { type: String, default: '', reflect: true },
|
|
53
64
|
};
|
|
54
65
|
|
|
55
66
|
static parts = {
|
|
@@ -62,6 +73,15 @@ export class UIAlert extends UIElement {
|
|
|
62
73
|
close: '<button-ui slot="close" icon="x" variant="ghost" size="sm" aria-label="Close"></button-ui>',
|
|
63
74
|
};
|
|
64
75
|
|
|
76
|
+
/* SPEC-006 \u2014 decline-reason \u2192 leading icon map. Used when
|
|
77
|
+
`pattern="dunning"` and no explicit [icon] override is set. */
|
|
78
|
+
static #DUNNING_ICONS = {
|
|
79
|
+
declined: 'x-circle',
|
|
80
|
+
expired: 'clock',
|
|
81
|
+
insufficient: 'wallet',
|
|
82
|
+
network: 'wifi-slash',
|
|
83
|
+
};
|
|
84
|
+
|
|
65
85
|
static template = () => null;
|
|
66
86
|
|
|
67
87
|
/**
|
|
@@ -100,7 +120,28 @@ export class UIAlert extends UIElement {
|
|
|
100
120
|
}
|
|
101
121
|
|
|
102
122
|
#onPress = (e) => {
|
|
103
|
-
if (e.target.closest('[slot="close"]'))
|
|
123
|
+
if (e.target.closest('[slot="close"]')) {
|
|
124
|
+
this.#close();
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
// SPEC-006 — dunning action delegation. Re-dispatch as a unified
|
|
128
|
+
// `dunning-action` event so downstream telemetry only listens once.
|
|
129
|
+
if (this.pattern === 'dunning') {
|
|
130
|
+
const trigger = e.target.closest('[data-dunning-action]');
|
|
131
|
+
if (trigger && this.contains(trigger)) {
|
|
132
|
+
const action = trigger.getAttribute('data-dunning-action') || '';
|
|
133
|
+
this.dispatchEvent(new CustomEvent('dunning-action', {
|
|
134
|
+
bubbles: true,
|
|
135
|
+
composed: true,
|
|
136
|
+
detail: {
|
|
137
|
+
action,
|
|
138
|
+
amount: this.amount,
|
|
139
|
+
currency: this.currency,
|
|
140
|
+
dueAt: this.dueAt,
|
|
141
|
+
},
|
|
142
|
+
}));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
104
145
|
};
|
|
105
146
|
|
|
106
147
|
connected() {
|
|
@@ -108,7 +149,7 @@ export class UIAlert extends UIElement {
|
|
|
108
149
|
this.#updateRole();
|
|
109
150
|
|
|
110
151
|
// Stamp default DOM if nothing was provided
|
|
111
|
-
if (this.icon) this.ensure('leading');
|
|
152
|
+
if (this.icon || (this.pattern === 'dunning' && this.reason)) this.ensure('leading');
|
|
112
153
|
this.ensure('content');
|
|
113
154
|
if (this.closable) this.ensure('close');
|
|
114
155
|
|
|
@@ -120,6 +161,15 @@ export class UIAlert extends UIElement {
|
|
|
120
161
|
}
|
|
121
162
|
|
|
122
163
|
render() {
|
|
164
|
+
// SPEC-006 — dunning pattern: branch into a separate render path
|
|
165
|
+
// that stamps Intl-formatted amount + due-date + reason into the
|
|
166
|
+
// content slot. The standard alert render path below is skipped.
|
|
167
|
+
if (this.pattern === 'dunning') {
|
|
168
|
+
this.#renderDunning();
|
|
169
|
+
this.#updateRole();
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
123
173
|
// Icon
|
|
124
174
|
if (this.icon) {
|
|
125
175
|
const leading = this.ensure('leading');
|
|
@@ -182,6 +232,143 @@ export class UIAlert extends UIElement {
|
|
|
182
232
|
this.#updateRole();
|
|
183
233
|
}
|
|
184
234
|
|
|
235
|
+
/**
|
|
236
|
+
* SPEC-006 — dunning render path.
|
|
237
|
+
*
|
|
238
|
+
* Stamps the content slot with a bolded title (per-reason copy) +
|
|
239
|
+
* a metadata line ("Card ending 4242 · declined May 20, 2026") +
|
|
240
|
+
* an Intl-formatted amount. The leading icon is selected from
|
|
241
|
+
* `#DUNNING_ICONS` keyed by the [reason] attribute (or [icon] if
|
|
242
|
+
* the consumer explicitly overrode).
|
|
243
|
+
*
|
|
244
|
+
* Re-runs on every render — formatting is stable + idempotent so a
|
|
245
|
+
* re-stamp produces the same DOM. We rebuild the content subtree
|
|
246
|
+
* each render to keep the auto-stamp markers from drifting between
|
|
247
|
+
* the dunning path and the standard path if [pattern] is toggled
|
|
248
|
+
* at runtime.
|
|
249
|
+
*/
|
|
250
|
+
#renderDunning() {
|
|
251
|
+
// Leading icon — explicit [icon] beats the reason map
|
|
252
|
+
const iconName = this.icon || UIAlert.#DUNNING_ICONS[this.reason] || 'x-circle';
|
|
253
|
+
const leading = this.ensure('leading');
|
|
254
|
+
if (leading) leading.setAttribute('name', iconName);
|
|
255
|
+
|
|
256
|
+
// Content
|
|
257
|
+
const content = this.ensure('content');
|
|
258
|
+
if (!content) return;
|
|
259
|
+
content.setAttribute('data-alert-auto', 'dunning');
|
|
260
|
+
content.replaceChildren();
|
|
261
|
+
|
|
262
|
+
// Title line — explicit [title] beats the per-reason default
|
|
263
|
+
const titleText = this.title || this.#defaultDunningTitle();
|
|
264
|
+
if (titleText) {
|
|
265
|
+
const strong = document.createElement('strong');
|
|
266
|
+
strong.setAttribute('data-dunning-title', '');
|
|
267
|
+
strong.textContent = titleText;
|
|
268
|
+
content.appendChild(strong);
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// Body line — formatted amount + metadata. We put amount first
|
|
272
|
+
// (it's the most-scanned datum) followed by the meta string.
|
|
273
|
+
const amountText = this.#formatAmount();
|
|
274
|
+
const metaText = this.#dunningMeta();
|
|
275
|
+
if (amountText || metaText) {
|
|
276
|
+
content.appendChild(document.createTextNode(' '));
|
|
277
|
+
if (amountText) {
|
|
278
|
+
const amt = document.createElement('span');
|
|
279
|
+
amt.setAttribute('data-dunning-amount', '');
|
|
280
|
+
amt.textContent = amountText;
|
|
281
|
+
content.appendChild(amt);
|
|
282
|
+
}
|
|
283
|
+
if (amountText && metaText) {
|
|
284
|
+
content.appendChild(document.createTextNode(' '));
|
|
285
|
+
}
|
|
286
|
+
if (metaText) {
|
|
287
|
+
const meta = document.createElement('span');
|
|
288
|
+
meta.setAttribute('data-dunning-meta', '');
|
|
289
|
+
meta.textContent = metaText;
|
|
290
|
+
content.appendChild(meta);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
// Composed accessible name — title + amount + meta in DOM order
|
|
295
|
+
const aria = [titleText, amountText, metaText].filter(Boolean).join('. ');
|
|
296
|
+
if (aria) this.setAttribute('aria-label', aria);
|
|
297
|
+
|
|
298
|
+
// Close button — dismissible-on-dunning is advisory-not-blocked
|
|
299
|
+
// (SPEC-006 OD-002 lean A). Pass through.
|
|
300
|
+
if (this.closable || this.dismissible) {
|
|
301
|
+
this.ensure('close');
|
|
302
|
+
} else {
|
|
303
|
+
this.drop('close');
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
#defaultDunningTitle() {
|
|
308
|
+
switch (this.reason) {
|
|
309
|
+
case 'expired': return 'Card expired';
|
|
310
|
+
case 'insufficient': return 'Insufficient funds';
|
|
311
|
+
case 'network': return 'Network error';
|
|
312
|
+
case 'declined': return 'Payment failed';
|
|
313
|
+
default: return this.variant === 'warning' ? 'Payment due soon' : 'Payment failed';
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
#formatAmount() {
|
|
318
|
+
if (!this.amount && this.amount !== 0) return '';
|
|
319
|
+
if (this.amount === 0) return '';
|
|
320
|
+
try {
|
|
321
|
+
const lang = this.getAttribute('lang') || this.lang || undefined;
|
|
322
|
+
return new Intl.NumberFormat(lang, {
|
|
323
|
+
style: 'currency',
|
|
324
|
+
currency: this.currency || 'USD',
|
|
325
|
+
}).format(this.amount);
|
|
326
|
+
} catch {
|
|
327
|
+
// Fallback if Intl rejects the currency code
|
|
328
|
+
return `${this.currency || ''} ${this.amount}`.trim();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
#formatDueDate() {
|
|
333
|
+
if (!this.dueAt) return '';
|
|
334
|
+
const d = new Date(this.dueAt);
|
|
335
|
+
if (Number.isNaN(d.getTime())) return '';
|
|
336
|
+
try {
|
|
337
|
+
const lang = this.getAttribute('lang') || this.lang || undefined;
|
|
338
|
+
return new Intl.DateTimeFormat(lang, {
|
|
339
|
+
year: 'numeric',
|
|
340
|
+
month: 'short',
|
|
341
|
+
day: 'numeric',
|
|
342
|
+
}).format(d);
|
|
343
|
+
} catch {
|
|
344
|
+
return d.toDateString();
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
#dunningMeta() {
|
|
349
|
+
const parts = [];
|
|
350
|
+
if (this.cardLast4) parts.push(`Card ending ${this.cardLast4}`);
|
|
351
|
+
if (this.reason && this.reason !== 'declined') {
|
|
352
|
+
parts.push(this.#reasonLabel());
|
|
353
|
+
}
|
|
354
|
+
const date = this.#formatDueDate();
|
|
355
|
+
if (date) {
|
|
356
|
+
const prefix = this.variant === 'warning' ? 'due' : 'failed';
|
|
357
|
+
parts.push(`${prefix} ${date}`);
|
|
358
|
+
}
|
|
359
|
+
return parts.join(' · ');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
#reasonLabel() {
|
|
363
|
+
switch (this.reason) {
|
|
364
|
+
case 'expired': return 'expired';
|
|
365
|
+
case 'insufficient': return 'insufficient funds';
|
|
366
|
+
case 'network': return 'network error';
|
|
367
|
+
case 'declined': return 'declined';
|
|
368
|
+
default: return '';
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
185
372
|
#updateRole() {
|
|
186
373
|
const role = (this.variant === 'danger' || this.variant === 'warning') ? 'alert' : 'status';
|
|
187
374
|
this.setAttribute('role', role);
|
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
@scope (alert-ui) {
|
|
2
2
|
:where(:scope) {
|
|
3
3
|
/* ── Colors ── */
|
|
4
|
-
--alert-bg: var(--a-bg-muted);
|
|
5
|
-
--alert-fg: var(--a-fg);
|
|
6
|
-
--alert-border: var(--a-border-subtle);
|
|
7
|
-
--alert-icon-fg: var(--a-fg-muted);
|
|
4
|
+
--alert-bg-default: var(--a-bg-muted);
|
|
5
|
+
--alert-fg-default: var(--a-fg);
|
|
6
|
+
--alert-border-default: var(--a-border-subtle);
|
|
7
|
+
--alert-icon-fg-default: var(--a-fg-muted);
|
|
8
8
|
|
|
9
9
|
/* ── Layout ── */
|
|
10
|
-
--alert-radius: var(--a-radius-md);
|
|
11
|
-
--alert-px: var(--a-space-3);
|
|
12
|
-
--alert-py: var(--a-space-2);
|
|
13
|
-
--alert-gap: var(--a-space-2);
|
|
10
|
+
--alert-radius-default: var(--a-radius-md);
|
|
11
|
+
--alert-px-default: var(--a-space-3);
|
|
12
|
+
--alert-py-default: var(--a-space-2);
|
|
13
|
+
--alert-gap-default: var(--a-space-2);
|
|
14
14
|
|
|
15
15
|
/* ── Typography ── */
|
|
16
|
-
--alert-font: var(--a-ui-size);
|
|
17
|
-
--alert-line-height: var(--a-ui-line-height, 1.5);
|
|
16
|
+
--alert-font-default: var(--a-ui-size);
|
|
17
|
+
--alert-line-height-default: var(--a-ui-line-height, 1.5);
|
|
18
|
+
|
|
19
|
+
/* ── SPEC-006 dunning pattern tokens ── */
|
|
20
|
+
--alert-amount-font-default: var(--a-font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
|
|
21
|
+
--alert-meta-fg-default: var(--a-fg-muted);
|
|
22
|
+
--alert-actions-gap-default: var(--a-space-2);
|
|
23
|
+
--alert-actions-mt-default: var(--a-space-2);
|
|
18
24
|
}
|
|
19
25
|
|
|
20
26
|
:scope {
|
|
@@ -26,43 +32,43 @@
|
|
|
26
32
|
text on multi-line alerts. The leading slot's own height = body
|
|
27
33
|
line-height (below) means the icon optically centers on line 1. */
|
|
28
34
|
align-items: start;
|
|
29
|
-
gap: var(--alert-gap);
|
|
30
|
-
padding: var(--alert-py) var(--alert-px);
|
|
31
|
-
border: 1px solid var(--alert-border);
|
|
32
|
-
border-radius: var(--alert-radius);
|
|
33
|
-
font-size: var(--alert-font);
|
|
34
|
-
line-height: var(--alert-line-height);
|
|
35
|
-
color: var(--alert-fg);
|
|
36
|
-
background: var(--alert-bg);
|
|
35
|
+
gap: var(--alert-gap, var(--alert-gap-default));
|
|
36
|
+
padding: var(--alert-py, var(--alert-py-default)) var(--alert-px, var(--alert-px-default));
|
|
37
|
+
border: 1px solid var(--alert-border, var(--alert-border-default));
|
|
38
|
+
border-radius: var(--alert-radius, var(--alert-radius-default));
|
|
39
|
+
font-size: var(--alert-font, var(--alert-font-default));
|
|
40
|
+
line-height: var(--alert-line-height, var(--alert-line-height-default));
|
|
41
|
+
color: var(--alert-fg, var(--alert-fg-default));
|
|
42
|
+
background: var(--alert-bg, var(--alert-bg-default));
|
|
37
43
|
}
|
|
38
44
|
|
|
39
45
|
/* ── Variants ── */
|
|
40
46
|
:scope[variant="info"] {
|
|
41
|
-
--alert-bg: var(--a-info-muted);
|
|
42
|
-
--alert-fg: var(--a-info-text);
|
|
43
|
-
--alert-border: var(--a-info-border-subtle);
|
|
44
|
-
--alert-icon-fg: var(--a-info-strong);
|
|
47
|
+
--alert-bg-default: var(--a-info-muted);
|
|
48
|
+
--alert-fg-default: var(--a-info-text);
|
|
49
|
+
--alert-border-default: var(--a-info-border-subtle);
|
|
50
|
+
--alert-icon-fg-default: var(--a-info-strong);
|
|
45
51
|
}
|
|
46
52
|
|
|
47
53
|
:scope[variant="success"] {
|
|
48
|
-
--alert-bg: var(--a-success-muted);
|
|
49
|
-
--alert-fg: var(--a-success-text);
|
|
50
|
-
--alert-border: var(--a-success-border-subtle);
|
|
51
|
-
--alert-icon-fg: var(--a-success-strong);
|
|
54
|
+
--alert-bg-default: var(--a-success-muted);
|
|
55
|
+
--alert-fg-default: var(--a-success-text);
|
|
56
|
+
--alert-border-default: var(--a-success-border-subtle);
|
|
57
|
+
--alert-icon-fg-default: var(--a-success-strong);
|
|
52
58
|
}
|
|
53
59
|
|
|
54
60
|
:scope[variant="warning"] {
|
|
55
|
-
--alert-bg: var(--a-warning-muted);
|
|
56
|
-
--alert-fg: var(--a-warning-text);
|
|
57
|
-
--alert-border: var(--a-warning-border-subtle);
|
|
58
|
-
--alert-icon-fg: var(--a-warning-strong);
|
|
61
|
+
--alert-bg-default: var(--a-warning-muted);
|
|
62
|
+
--alert-fg-default: var(--a-warning-text);
|
|
63
|
+
--alert-border-default: var(--a-warning-border-subtle);
|
|
64
|
+
--alert-icon-fg-default: var(--a-warning-strong);
|
|
59
65
|
}
|
|
60
66
|
|
|
61
67
|
:scope[variant="danger"] {
|
|
62
|
-
--alert-bg: var(--a-danger-muted);
|
|
63
|
-
--alert-fg: var(--a-danger-text);
|
|
64
|
-
--alert-border: var(--a-danger-border-subtle);
|
|
65
|
-
--alert-icon-fg: var(--a-danger-strong);
|
|
68
|
+
--alert-bg-default: var(--a-danger-muted);
|
|
69
|
+
--alert-fg-default: var(--a-danger-text);
|
|
70
|
+
--alert-border-default: var(--a-danger-border-subtle);
|
|
71
|
+
--alert-icon-fg-default: var(--a-danger-strong);
|
|
66
72
|
}
|
|
67
73
|
|
|
68
74
|
/* `muted` and `neutral` are semantic aliases of the base — same tokens
|
|
@@ -72,21 +78,21 @@
|
|
|
72
78
|
than carrying tonal weight. */
|
|
73
79
|
:scope[variant="muted"],
|
|
74
80
|
:scope[variant="neutral"] {
|
|
75
|
-
--alert-bg: var(--a-bg-muted);
|
|
76
|
-
--alert-fg: var(--a-fg);
|
|
77
|
-
--alert-border: var(--a-border-subtle);
|
|
78
|
-
--alert-icon-fg: var(--a-fg-muted);
|
|
81
|
+
--alert-bg-default: var(--a-bg-muted);
|
|
82
|
+
--alert-fg-default: var(--a-fg);
|
|
83
|
+
--alert-border-default: var(--a-border-subtle);
|
|
84
|
+
--alert-icon-fg-default: var(--a-fg-muted);
|
|
79
85
|
}
|
|
80
86
|
|
|
81
87
|
/* ── Slots ── */
|
|
82
88
|
:scope [slot="leading"] {
|
|
83
89
|
flex-shrink: 0;
|
|
84
|
-
color: var(--alert-icon-fg);
|
|
90
|
+
color: var(--alert-icon-fg, var(--alert-icon-fg-default));
|
|
85
91
|
/* Box height = one line of body so the icon optical-centers on the
|
|
86
92
|
first line under `align-items: start`. */
|
|
87
93
|
display: inline-flex;
|
|
88
94
|
align-items: center;
|
|
89
|
-
min-height: calc(var(--alert-font) * var(--alert-line-height));
|
|
95
|
+
min-height: calc(var(--alert-font, var(--alert-font-default)) * var(--alert-line-height, var(--alert-line-height-default)));
|
|
90
96
|
/* `ensure()` appends the leading-slot icon to the host, which
|
|
91
97
|
puts it after any consumer-provided content in DOM order.
|
|
92
98
|
Force it to the visual lead via flex `order` so the icon
|
|
@@ -113,6 +119,78 @@
|
|
|
113
119
|
sit on the same first-line baseline. */
|
|
114
120
|
:scope [slot="close"] {
|
|
115
121
|
flex-shrink: 0;
|
|
116
|
-
min-height: calc(var(--alert-font) * var(--alert-line-height));
|
|
122
|
+
min-height: calc(var(--alert-font, var(--alert-font-default)) * var(--alert-line-height, var(--alert-line-height-default)));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/* ──────────────────────────────────────────────────────────────
|
|
126
|
+
SPEC-006 — Dunning / Payment-Failed pattern
|
|
127
|
+
──────────────────────────────────────────────────────────────
|
|
128
|
+
`pattern="dunning"` switches the alert into a billing notice
|
|
129
|
+
layout. The default alert is a single-row flex container; the
|
|
130
|
+
dunning mode keeps the leading icon and close button in a
|
|
131
|
+
"header" row but stacks the content + actions vertically below.
|
|
132
|
+
|
|
133
|
+
We achieve this by switching the host to `flex-wrap: wrap` and
|
|
134
|
+
assigning `order` per slot. The standard alert children authored
|
|
135
|
+
in arbitrary DOM order (buttons before content is the common
|
|
136
|
+
consumer mistake) are visually re-ordered by these rules so the
|
|
137
|
+
final layout always reads icon → content → actions → close. */
|
|
138
|
+
|
|
139
|
+
:scope[pattern="dunning"] {
|
|
140
|
+
flex-wrap: wrap;
|
|
141
|
+
row-gap: var(--alert-actions-mt, var(--alert-actions-mt-default));
|
|
142
|
+
/* Use align-items: flex-start so the leading icon hugs the top
|
|
143
|
+
of the message regardless of how tall the content + actions
|
|
144
|
+
column grows. */
|
|
145
|
+
align-items: flex-start;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/* Visual order — icon first, then content, then actions, then
|
|
149
|
+
close. Source DOM order is irrelevant under these rules. The
|
|
150
|
+
`order` integers leave room (10/20/30/40) for future expansion
|
|
151
|
+
without renumbering. */
|
|
152
|
+
:scope[pattern="dunning"] [slot="leading"] { order: 10; }
|
|
153
|
+
:scope[pattern="dunning"] [slot="content"] { order: 20; }
|
|
154
|
+
:scope[pattern="dunning"] [slot="actions"] { order: 30; }
|
|
155
|
+
:scope[pattern="dunning"] [slot="close"] { order: 40; }
|
|
156
|
+
|
|
157
|
+
:scope[pattern="dunning"] [data-dunning-amount] {
|
|
158
|
+
font-family: var(--alert-amount-font, var(--alert-amount-font-default));
|
|
159
|
+
font-variant-numeric: tabular-nums;
|
|
160
|
+
font-weight: 600;
|
|
161
|
+
/* Inherit color from the variant; tabular-nums + monospace make
|
|
162
|
+
the amount the scannable focal datum. */
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
:scope[pattern="dunning"] [data-dunning-meta] {
|
|
166
|
+
color: var(--alert-meta-fg, var(--alert-meta-fg-default));
|
|
167
|
+
font-size: calc(var(--alert-font, var(--alert-font-default)) * 0.9375);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
:scope[pattern="dunning"] [data-dunning-title] {
|
|
171
|
+
display: inline-block;
|
|
172
|
+
margin-inline-end: var(--a-space-1, 0.25rem);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Actions slot — sits below the content as a row of buttons.
|
|
176
|
+
`flex-basis: 100%` combined with the `order: 30` rule pushes
|
|
177
|
+
the actions onto their own row after the content row. The
|
|
178
|
+
padding-inline-start indents the buttons under the message
|
|
179
|
+
column (so they left-align with the body text, not the leading
|
|
180
|
+
icon). */
|
|
181
|
+
:scope[pattern="dunning"] [slot="actions"] {
|
|
182
|
+
flex-basis: 100%;
|
|
183
|
+
display: flex;
|
|
184
|
+
flex-wrap: wrap;
|
|
185
|
+
gap: var(--alert-actions-gap, var(--alert-actions-gap-default));
|
|
186
|
+
padding-inline-start: calc(var(--alert-font, var(--alert-font-default)) + var(--alert-gap, var(--alert-gap-default)));
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/* Lenient — when a bare button-ui carries data-dunning-action but
|
|
190
|
+
no explicit slot=actions, give it the same visual order as the
|
|
191
|
+
actions group so authoring oversights don't break layout. */
|
|
192
|
+
:scope[pattern="dunning"] > [data-dunning-action]:not([slot]) {
|
|
193
|
+
order: 30;
|
|
194
|
+
flex-basis: 100%;
|
|
117
195
|
}
|
|
118
196
|
}
|
|
@@ -21,18 +21,31 @@ inline upgrade prompts.
|
|
|
21
21
|
import { UIElement } from '../../core/element.js';
|
|
22
22
|
|
|
23
23
|
export type AlertCloseEvent = CustomEvent<unknown>;
|
|
24
|
+
export type AlertDunningActionEvent = CustomEvent<unknown>;
|
|
24
25
|
|
|
25
26
|
export class UIAlert extends UIElement {
|
|
26
27
|
/** Bold headline rendered as the first line of the alert content. Pair with [description] for the canonical "banner" pattern (headline + body). When [title] or [description] is set, the [text] prop is ignored. */
|
|
27
28
|
title: string;
|
|
28
29
|
/** Body text rendered as the second line of the alert content, below [title]. May be used alone (without [title]) for a single muted-body message. */
|
|
29
30
|
description: string;
|
|
31
|
+
/** Dunning mode only — the unpaid amount as a decimal major-unit number (`24.50`, not minor units like `2450`). Formatted via `Intl.NumberFormat` using [currency] and [lang]. Ignored when [pattern] is not `dunning`. */
|
|
32
|
+
amount: number;
|
|
33
|
+
/** Dunning mode only — last 4 digits of the declined card. Rendered as "ending 4242". Ignored when [pattern] is not `dunning`. Attribute spelling: `card-last4`. */
|
|
34
|
+
cardLast4: string;
|
|
30
35
|
/** Whether a close button is displayed. Alias [dismissible] is also accepted (same semantics, different spelling — the corpus and many libraries use both; both map to the same state). */
|
|
31
36
|
closable: boolean;
|
|
37
|
+
/** Dunning mode only — ISO 4217 currency code driving the `Intl.NumberFormat` style="currency" rendering. Defaults to `USD`. */
|
|
38
|
+
currency: string;
|
|
32
39
|
/** Public alias for [closable] — same semantics. Both attributes render the close button. Use whichever spelling matches your authoring style. */
|
|
33
40
|
dismissible: boolean;
|
|
41
|
+
/** Dunning mode only — ISO 8601 due / failed-at timestamp. Formatted via `Intl.DateTimeFormat`. Ignored when [pattern] is not `dunning`. Attribute spelling: `due-at`. */
|
|
42
|
+
dueAt: string;
|
|
34
43
|
/** Icon identifier displayed before the message content */
|
|
35
44
|
icon: string;
|
|
45
|
+
/** Domain pattern mode. Default is empty (standard alert). Setting `pattern="dunning"` switches to billing dunning render mode — stamps a formatted amount + due-date + decline-reason from props and re-dispatches descendant `[data-dunning-action]` button clicks as a unified `dunning-action` event. Spec: SPEC-006. */
|
|
46
|
+
pattern: '' | 'dunning';
|
|
47
|
+
/** Dunning mode only — decline reason. Drives the leading icon (declined → `x-circle`, expired → `clock`, insufficient → `wallet`, network → `wifi-slash`). One of: `declined`, `expired`, `insufficient`, `network`, or empty. */
|
|
48
|
+
reason: '' | 'declined' | 'expired' | 'insufficient' | 'network';
|
|
36
49
|
/** Single-line alert message. For two-line "headline + body" alerts, use [title] + [description] instead. For rich content (links, formatting), use the [slot="content"] slot. */
|
|
37
50
|
text: string;
|
|
38
51
|
/** Semantic color variant. */
|
|
@@ -44,4 +57,5 @@ export class UIAlert extends UIElement {
|
|
|
44
57
|
options?: boolean | AddEventListenerOptions,
|
|
45
58
|
): void;
|
|
46
59
|
addEventListener(type: 'close', listener: (ev: AlertCloseEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
60
|
+
addEventListener(type: 'dunning-action', listener: (ev: AlertDunningActionEvent) => unknown, options?: boolean | AddEventListenerOptions): void;
|
|
47
61
|
}
|