@adia-ai/web-components 0.6.34 → 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 +42 -0
- package/color/index.js +1 -1
- package/components/accordion/accordion-item.yaml +2 -2
- package/components/accordion/accordion.js +1 -1
- package/components/action-list/action-item.yaml +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.js +1 -1
- package/components/agent-feedback-bar/agent-feedback-bar.js +1 -1
- package/components/agent-questions/agent-questions.js +1 -1
- package/components/agent-reasoning/agent-reasoning.js +1 -1
- package/components/agent-suggestions/agent-suggestions.js +1 -1
- package/components/alert/alert.a2ui.json +64 -1
- package/components/alert/{class.js → alert.class.js} +189 -2
- package/components/alert/alert.css +78 -0
- 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.js +1 -1
- package/components/badge/badge.js +1 -1
- package/components/block/block.js +1 -1
- package/components/breadcrumb/breadcrumb.js +1 -1
- package/components/button/button.js +1 -1
- package/components/calendar-grid/calendar-grid.a2ui.json +10 -0
- package/components/calendar-grid/{class.js → calendar-grid.class.js} +30 -4
- package/components/calendar-grid/calendar-grid.css +20 -0
- package/components/calendar-grid/calendar-grid.d.ts +4 -0
- package/components/calendar-grid/calendar-grid.js +1 -1
- package/components/calendar-grid/calendar-grid.yaml +20 -0
- package/components/calendar-picker/calendar-picker.js +1 -1
- package/components/card/card.js +1 -1
- package/components/chart/chart.js +1 -1
- 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.js +1 -1
- package/components/code/code.js +1 -1
- package/components/col/col.js +1 -1
- package/components/color-input/color-input.js +1 -1
- package/components/color-picker/color-picker.js +1 -1
- package/components/combobox/combobox.js +1 -1
- package/components/command/command.js +1 -1
- package/components/date-range-picker/{class.js → date-range-picker.class.js} +18 -2
- package/components/date-range-picker/date-range-picker.css +51 -5
- package/components/date-range-picker/date-range-picker.js +1 -1
- package/components/datetime-picker/{class.js → datetime-picker.class.js} +1 -1
- package/components/datetime-picker/datetime-picker.js +1 -1
- package/components/demo-toggle/demo-toggle.js +1 -1
- package/components/description-list/description-list.js +1 -1
- package/components/divider/divider.js +1 -1
- package/components/drawer/drawer.js +1 -1
- package/components/embed/embed.js +1 -1
- package/components/empty-state/empty-state.js +1 -1
- package/components/feed/feed.js +1 -1
- package/components/field/field.js +1 -1
- package/components/field/field.test.js +1 -1
- package/components/fields/fields.js +1 -1
- package/components/grid/grid.js +1 -1
- package/components/heatmap/heatmap.js +1 -1
- package/components/icon/icon.js +1 -1
- package/components/image/image.js +1 -1
- package/components/index.js +3 -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 +1 -1
- package/components/input/input.js +1 -1
- package/components/input/input.yaml +5 -4
- package/components/inspector/inspector.js +1 -1
- package/components/integration-card/integration-card.js +1 -1
- package/components/kbd/kbd.js +1 -1
- package/components/link/link.js +1 -1
- package/components/list/list-item.yaml +2 -2
- package/components/list/list.js +1 -1
- package/components/list-window/list-window.js +1 -1
- 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.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 +11 -1
- package/components/modal/modal.js +1 -1
- package/components/nav/nav.js +1 -1
- package/components/nav-group/nav-group.js +1 -1
- package/components/nav-item/nav-item.js +1 -1
- package/components/noodles/noodles.js +1 -1
- package/components/option-card/option-card.js +1 -1
- package/components/otp-input/otp-input.js +1 -1
- package/components/page/page.js +1 -1
- package/components/pagination/pagination.js +1 -1
- package/components/pane/pane.js +1 -1
- package/components/pipeline-status/pipeline-status.js +1 -1
- package/components/popover/popover.a2ui.json +8 -1
- package/components/popover/popover.js +1 -1
- package/components/popover/popover.yaml +14 -1
- package/components/progress/progress.js +1 -1
- package/components/progress-row/progress-row.js +1 -1
- package/components/radio/radio.js +1 -1
- package/components/range/range.js +1 -1
- package/components/rating/rating.js +1 -1
- package/components/richtext/richtext.js +1 -1
- package/components/row/row.js +1 -1
- package/components/search/search.js +1 -1
- package/components/segment/segment.js +1 -1
- 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 +158 -0
- 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.js +1 -1
- package/components/slider/slider.js +1 -1
- package/components/spinner/spinner.a2ui.json +3 -2
- package/components/spinner/{class.js → spinner.class.js} +33 -3
- package/components/spinner/spinner.css +91 -35
- package/components/spinner/spinner.d.ts +2 -2
- package/components/spinner/spinner.js +1 -1
- package/components/spinner/spinner.test.js +49 -11
- package/components/spinner/spinner.yaml +9 -1
- package/components/stack/stack.js +1 -1
- package/components/step-progress/step-progress.js +1 -1
- package/components/stepper/stepper-item.yaml +1 -1
- package/components/stepper/stepper.js +1 -1
- package/components/stream/stream.js +1 -1
- package/components/swatch/swatch.js +1 -1
- package/components/swiper/swiper.js +1 -1
- package/components/switch/switch.js +1 -1
- package/components/table/table.css +1 -1
- 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.js +1 -1
- package/components/tabs/tab.yaml +2 -2
- package/components/tabs/tabs.js +1 -1
- 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.js +1 -1
- package/components/textarea/textarea.a2ui.json +1 -1
- package/components/textarea/textarea.js +1 -1
- package/components/textarea/textarea.yaml +11 -8
- package/components/time-picker/time-picker.js +1 -1
- package/components/timeline/timeline-item.yaml +2 -2
- package/components/timeline/{class.js → timeline.class.js} +1 -1
- package/components/timeline/timeline.js +1 -1
- package/components/toast/toast.js +1 -1
- package/components/toggle-group/toggle-group.js +1 -1
- package/components/toggle-group/toggle-option.yaml +1 -1
- package/components/toggle-scheme/toggle-scheme.js +1 -1
- package/components/toolbar/toolbar-group.yaml +1 -1
- package/components/toolbar/toolbar.js +1 -1
- package/components/tooltip/tooltip.js +1 -1
- package/components/tree/tree-item.yaml +1 -1
- package/components/tree/tree.js +1 -1
- package/components/upload/upload.js +1 -1
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +111 -90
- package/package.json +3 -3
- package/styles/components.css +3 -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/combobox/{class.js → combobox.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/integration-card/{class.js → integration-card.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/list-window/{class.js → list-window.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/time-picker/{class.js → time-picker.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
|
@@ -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
|
}
|
|
@@ -178,3 +178,187 @@ describe('alert-ui — full corpus shape (the §34 scenario)', () => {
|
|
|
178
178
|
expect(content.querySelector('a').getAttribute('href')).toBe('/foo');
|
|
179
179
|
});
|
|
180
180
|
});
|
|
181
|
+
|
|
182
|
+
describe('alert-ui — SPEC-006 dunning pattern', () => {
|
|
183
|
+
beforeEach(() => { document.body.innerHTML = ''; });
|
|
184
|
+
|
|
185
|
+
it('formats amount via Intl.NumberFormat with currency', async () => {
|
|
186
|
+
const a = mount(`<alert-ui pattern="dunning" amount="24.50" currency="USD"
|
|
187
|
+
due-at="2026-05-20" card-last4="4242"
|
|
188
|
+
reason="declined" variant="danger"></alert-ui>`);
|
|
189
|
+
await tick();
|
|
190
|
+
const amt = a.querySelector('[data-dunning-amount]');
|
|
191
|
+
expect(amt).not.toBeNull();
|
|
192
|
+
// en-US default formatting (jsdom): "$24.50"
|
|
193
|
+
expect(amt.textContent).toMatch(/\$24\.50|USD\s*24\.50/);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
it('formats due date via Intl.DateTimeFormat', async () => {
|
|
197
|
+
const a = mount(`<alert-ui pattern="dunning" amount="24.50" currency="USD"
|
|
198
|
+
due-at="2026-05-20T00:00:00Z"
|
|
199
|
+
reason="declined" variant="danger"></alert-ui>`);
|
|
200
|
+
await tick();
|
|
201
|
+
const meta = a.querySelector('[data-dunning-meta]');
|
|
202
|
+
expect(meta).not.toBeNull();
|
|
203
|
+
// Expect month name + day + year somewhere in the meta
|
|
204
|
+
expect(meta.textContent).toMatch(/May/);
|
|
205
|
+
expect(meta.textContent).toMatch(/2026/);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('stamps the cardLast4 metadata', async () => {
|
|
209
|
+
const a = mount(`<alert-ui pattern="dunning" amount="24.50" currency="USD"
|
|
210
|
+
due-at="2026-05-20" card-last4="4242"
|
|
211
|
+
reason="declined" variant="danger"></alert-ui>`);
|
|
212
|
+
await tick();
|
|
213
|
+
const meta = a.querySelector('[data-dunning-meta]');
|
|
214
|
+
expect(meta.textContent).toContain('ending 4242');
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
it('stamps x-circle icon for reason="declined"', async () => {
|
|
218
|
+
const a = mount(`<alert-ui pattern="dunning" reason="declined" variant="danger"
|
|
219
|
+
amount="10" currency="USD"></alert-ui>`);
|
|
220
|
+
await tick();
|
|
221
|
+
const icon = a.querySelector('[slot="leading"]');
|
|
222
|
+
expect(icon).not.toBeNull();
|
|
223
|
+
expect(icon.getAttribute('name')).toBe('x-circle');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('stamps clock icon for reason="expired"', async () => {
|
|
227
|
+
const a = mount(`<alert-ui pattern="dunning" reason="expired" variant="danger"
|
|
228
|
+
amount="10" currency="USD"></alert-ui>`);
|
|
229
|
+
await tick();
|
|
230
|
+
const icon = a.querySelector('[slot="leading"]');
|
|
231
|
+
expect(icon.getAttribute('name')).toBe('clock');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('dispatches dunning-action event on descendant [data-dunning-action] click', async () => {
|
|
235
|
+
const a = mount(`<alert-ui pattern="dunning" amount="24.50" currency="USD"
|
|
236
|
+
due-at="2026-05-20" reason="declined" variant="danger">
|
|
237
|
+
<button-ui slot="actions" data-dunning-action="update" text="Update"></button-ui>
|
|
238
|
+
<button-ui slot="actions" data-dunning-action="retry" text="Retry"></button-ui>
|
|
239
|
+
</alert-ui>`);
|
|
240
|
+
await tick();
|
|
241
|
+
|
|
242
|
+
const received = [];
|
|
243
|
+
a.addEventListener('dunning-action', (e) => received.push(e.detail));
|
|
244
|
+
|
|
245
|
+
const updateBtn = a.querySelector('[data-dunning-action="update"]');
|
|
246
|
+
updateBtn.dispatchEvent(new Event('press', { bubbles: true }));
|
|
247
|
+
await tick();
|
|
248
|
+
|
|
249
|
+
expect(received.length).toBe(1);
|
|
250
|
+
expect(received[0].action).toBe('update');
|
|
251
|
+
expect(received[0].amount).toBe(24.5);
|
|
252
|
+
expect(received[0].currency).toBe('USD');
|
|
253
|
+
expect(received[0].dueAt).toBe('2026-05-20');
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
it('dispatches dunning-action with action="retry" when retry button is pressed', async () => {
|
|
257
|
+
const a = mount(`<alert-ui pattern="dunning" amount="10" currency="USD"
|
|
258
|
+
due-at="2026-05-20" reason="declined" variant="danger">
|
|
259
|
+
<button-ui slot="actions" data-dunning-action="retry" text="Retry"></button-ui>
|
|
260
|
+
</alert-ui>`);
|
|
261
|
+
await tick();
|
|
262
|
+
|
|
263
|
+
const received = [];
|
|
264
|
+
a.addEventListener('dunning-action', (e) => received.push(e.detail));
|
|
265
|
+
|
|
266
|
+
const retryBtn = a.querySelector('[data-dunning-action="retry"]');
|
|
267
|
+
retryBtn.dispatchEvent(new Event('press', { bubbles: true }));
|
|
268
|
+
await tick();
|
|
269
|
+
|
|
270
|
+
expect(received.length).toBe(1);
|
|
271
|
+
expect(received[0].action).toBe('retry');
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
it('re-formats amount when the [amount] attribute changes', async () => {
|
|
275
|
+
const a = mount(`<alert-ui pattern="dunning" amount="10" currency="USD"
|
|
276
|
+
due-at="2026-05-20" reason="declined" variant="danger"></alert-ui>`);
|
|
277
|
+
await tick();
|
|
278
|
+
let amt = a.querySelector('[data-dunning-amount]');
|
|
279
|
+
expect(amt.textContent).toMatch(/10/);
|
|
280
|
+
|
|
281
|
+
a.amount = 99.99;
|
|
282
|
+
await tick();
|
|
283
|
+
amt = a.querySelector('[data-dunning-amount]');
|
|
284
|
+
expect(amt.textContent).toMatch(/99\.99/);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('inherits role="alert" for variant="danger" in dunning mode', async () => {
|
|
288
|
+
const a = mount(`<alert-ui pattern="dunning" variant="danger" amount="10" currency="USD"
|
|
289
|
+
due-at="2026-05-20" reason="declined"></alert-ui>`);
|
|
290
|
+
await tick();
|
|
291
|
+
expect(a.getAttribute('role')).toBe('alert');
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('inherits role="alert" for variant="warning" (grace period)', async () => {
|
|
295
|
+
const a = mount(`<alert-ui pattern="dunning" variant="warning" amount="10" currency="USD"
|
|
296
|
+
due-at="2026-06-01"></alert-ui>`);
|
|
297
|
+
await tick();
|
|
298
|
+
// warning maps to role=alert (same as danger via #updateRole)
|
|
299
|
+
expect(a.getAttribute('role')).toBe('alert');
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
it('grace-period (warning) uses "due" prefix in date meta, not "failed"', async () => {
|
|
303
|
+
const a = mount(`<alert-ui pattern="dunning" variant="warning" amount="10" currency="USD"
|
|
304
|
+
due-at="2026-06-01"></alert-ui>`);
|
|
305
|
+
await tick();
|
|
306
|
+
const meta = a.querySelector('[data-dunning-meta]');
|
|
307
|
+
expect(meta.textContent).toContain('due');
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('default title for declined is "Payment failed"', async () => {
|
|
311
|
+
const a = mount(`<alert-ui pattern="dunning" reason="declined" variant="danger"
|
|
312
|
+
amount="10" currency="USD"></alert-ui>`);
|
|
313
|
+
await tick();
|
|
314
|
+
const titleEl = a.querySelector('[data-dunning-title]');
|
|
315
|
+
expect(titleEl.textContent).toBe('Payment failed');
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('default title for expired is "Card expired"', async () => {
|
|
319
|
+
const a = mount(`<alert-ui pattern="dunning" reason="expired" variant="danger"
|
|
320
|
+
amount="10" currency="USD"></alert-ui>`);
|
|
321
|
+
await tick();
|
|
322
|
+
const titleEl = a.querySelector('[data-dunning-title]');
|
|
323
|
+
expect(titleEl.textContent).toBe('Card expired');
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('explicit [title] overrides the per-reason default', async () => {
|
|
327
|
+
const a = mount(`<alert-ui pattern="dunning" reason="declined" title="Custom message"
|
|
328
|
+
amount="10" currency="USD" variant="danger"></alert-ui>`);
|
|
329
|
+
await tick();
|
|
330
|
+
const titleEl = a.querySelector('[data-dunning-title]');
|
|
331
|
+
expect(titleEl.textContent).toBe('Custom message');
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('explicit [icon] overrides the per-reason icon map', async () => {
|
|
335
|
+
const a = mount(`<alert-ui pattern="dunning" reason="declined" icon="credit-card"
|
|
336
|
+
amount="10" currency="USD" variant="danger"></alert-ui>`);
|
|
337
|
+
await tick();
|
|
338
|
+
const icon = a.querySelector('[slot="leading"]');
|
|
339
|
+
expect(icon.getAttribute('name')).toBe('credit-card');
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('composes aria-label from title + amount + meta', async () => {
|
|
343
|
+
const a = mount(`<alert-ui pattern="dunning" reason="declined" amount="24.50"
|
|
344
|
+
currency="USD" due-at="2026-05-20" card-last4="4242"
|
|
345
|
+
variant="danger"></alert-ui>`);
|
|
346
|
+
await tick();
|
|
347
|
+
const aria = a.getAttribute('aria-label');
|
|
348
|
+
expect(aria).toContain('Payment failed');
|
|
349
|
+
expect(aria).toMatch(/24\.50/);
|
|
350
|
+
expect(aria).toMatch(/4242/);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('does not stamp dunning content when pattern is empty (standard mode)', async () => {
|
|
354
|
+
const a = mount(`<alert-ui variant="danger" amount="24.50" currency="USD"
|
|
355
|
+
due-at="2026-05-20" reason="declined"
|
|
356
|
+
text="standard message"></alert-ui>`);
|
|
357
|
+
await tick();
|
|
358
|
+
// No dunning markers — uses the standard text-only render path
|
|
359
|
+
expect(a.querySelector('[data-dunning-amount]')).toBeNull();
|
|
360
|
+
expect(a.querySelector('[data-dunning-title]')).toBeNull();
|
|
361
|
+
const content = a.querySelector(':scope > [slot="content"]');
|
|
362
|
+
expect(content.textContent.trim()).toBe('standard message');
|
|
363
|
+
});
|
|
364
|
+
});
|
|
@@ -69,9 +69,73 @@ props:
|
|
|
69
69
|
- danger
|
|
70
70
|
- muted
|
|
71
71
|
- neutral
|
|
72
|
+
pattern:
|
|
73
|
+
description: >-
|
|
74
|
+
Domain pattern mode. Default is empty (standard alert). Setting
|
|
75
|
+
`pattern="dunning"` switches to billing dunning render mode —
|
|
76
|
+
stamps a formatted amount + due-date + decline-reason from props
|
|
77
|
+
and re-dispatches descendant `[data-dunning-action]` button
|
|
78
|
+
clicks as a unified `dunning-action` event. Spec: SPEC-006.
|
|
79
|
+
type: string
|
|
80
|
+
default: ""
|
|
81
|
+
enum:
|
|
82
|
+
- ""
|
|
83
|
+
- dunning
|
|
84
|
+
amount:
|
|
85
|
+
description: >-
|
|
86
|
+
Dunning mode only — the unpaid amount as a decimal major-unit
|
|
87
|
+
number (`24.50`, not minor units like `2450`). Formatted via
|
|
88
|
+
`Intl.NumberFormat` using [currency] and [lang]. Ignored when
|
|
89
|
+
[pattern] is not `dunning`.
|
|
90
|
+
type: number
|
|
91
|
+
default: 0
|
|
92
|
+
currency:
|
|
93
|
+
description: >-
|
|
94
|
+
Dunning mode only — ISO 4217 currency code driving the
|
|
95
|
+
`Intl.NumberFormat` style="currency" rendering. Defaults to
|
|
96
|
+
`USD`.
|
|
97
|
+
type: string
|
|
98
|
+
default: USD
|
|
99
|
+
dueAt:
|
|
100
|
+
description: >-
|
|
101
|
+
Dunning mode only — ISO 8601 due / failed-at timestamp.
|
|
102
|
+
Formatted via `Intl.DateTimeFormat`. Ignored when [pattern] is
|
|
103
|
+
not `dunning`. Attribute spelling: `due-at`.
|
|
104
|
+
type: string
|
|
105
|
+
default: ""
|
|
106
|
+
attribute: due-at
|
|
107
|
+
cardLast4:
|
|
108
|
+
description: >-
|
|
109
|
+
Dunning mode only — last 4 digits of the declined card.
|
|
110
|
+
Rendered as "ending 4242". Ignored when [pattern] is not
|
|
111
|
+
`dunning`. Attribute spelling: `card-last4`.
|
|
112
|
+
type: string
|
|
113
|
+
default: ""
|
|
114
|
+
attribute: card-last4
|
|
115
|
+
reason:
|
|
116
|
+
description: >-
|
|
117
|
+
Dunning mode only — decline reason. Drives the leading icon
|
|
118
|
+
(declined → `x-circle`, expired → `clock`, insufficient →
|
|
119
|
+
`wallet`, network → `wifi-slash`). One of: `declined`,
|
|
120
|
+
`expired`, `insufficient`, `network`, or empty.
|
|
121
|
+
type: string
|
|
122
|
+
default: ""
|
|
123
|
+
enum:
|
|
124
|
+
- ""
|
|
125
|
+
- declined
|
|
126
|
+
- expired
|
|
127
|
+
- insufficient
|
|
128
|
+
- network
|
|
72
129
|
events:
|
|
73
130
|
close:
|
|
74
131
|
description: Fired when the close button is clicked
|
|
132
|
+
dunning-action:
|
|
133
|
+
description: >-
|
|
134
|
+
Dunning pattern only — fired when a descendant button with
|
|
135
|
+
`[data-dunning-action]` is clicked. Detail shape `{ action,
|
|
136
|
+
amount, currency, dueAt }`; the action string is the value of
|
|
137
|
+
the `data-dunning-action` attribute (typically `"update"` or
|
|
138
|
+
`"retry"`).
|
|
75
139
|
slots:
|
|
76
140
|
content:
|
|
77
141
|
description: >-
|
|
@@ -94,6 +158,12 @@ slots:
|
|
|
94
158
|
Optional trailing action button (e.g. "Refresh", "Status page").
|
|
95
159
|
Right-aligned in the flex layout. See system-banners pattern for
|
|
96
160
|
examples.
|
|
161
|
+
actions:
|
|
162
|
+
description: >-
|
|
163
|
+
Dunning pattern only — action button stack (typically two
|
|
164
|
+
`<button-ui>` with `data-dunning-action="update"` and
|
|
165
|
+
`data-dunning-action="retry"`). Sits below the formatted message
|
|
166
|
+
in the col layout when `pattern="dunning"`.
|
|
97
167
|
states:
|
|
98
168
|
- name: idle
|
|
99
169
|
description: Default, ready for interaction.
|
|
@@ -107,7 +177,19 @@ a2ui:
|
|
|
107
177
|
reason: 'Ephemeral vs persistent boundary.'
|
|
108
178
|
- rule: 'For modal-style critical alerts use <modal-ui> with alert content.'
|
|
109
179
|
reason: 'Inline vs modal.'
|
|
110
|
-
|
|
180
|
+
- rule: 'Billing dunning / payment-failed notices use pattern="dunning" + amount + currency + dueAt props, NOT inlined into title/description strings.'
|
|
181
|
+
reason: 'Intl-formatting + unified telemetry via dunning-action event.'
|
|
182
|
+
- rule: 'pattern="dunning" SHOULD use variant="danger" (default) or variant="warning" (grace period); never variant="info" or "success".'
|
|
183
|
+
reason: 'Dunning is always a failure surface.'
|
|
184
|
+
- rule: 'When pattern="dunning", slot at least one button-ui in slot="actions" with data-dunning-action ("update" or "retry").'
|
|
185
|
+
reason: 'No actions = no resolution path.'
|
|
186
|
+
anti_patterns:
|
|
187
|
+
- wrong: '<alert-ui pattern="dunning" variant="info">'
|
|
188
|
+
why: 'Dunning is always a failure surface; info mis-signals severity.'
|
|
189
|
+
fix: '<alert-ui pattern="dunning" variant="danger">'
|
|
190
|
+
- wrong: '<alert-ui pattern="dunning" title="Payment failed $24.50">'
|
|
191
|
+
why: 'Amount baked into title defeats Intl formatting + telemetry.'
|
|
192
|
+
fix: '<alert-ui pattern="dunning" amount="24.50" currency="USD" due-at="2026-05-20">'
|
|
111
193
|
examples:
|
|
112
194
|
- name: alert-banner
|
|
113
195
|
description: Single alert component with icon and dismiss action.
|
|
@@ -164,6 +246,37 @@ examples:
|
|
|
164
246
|
"variant": "primary"
|
|
165
247
|
}
|
|
166
248
|
]
|
|
249
|
+
- name: dunning-payment-failed
|
|
250
|
+
description: Billing dunning banner — declined card with retry + update-card actions (SPEC-006).
|
|
251
|
+
a2ui: >-
|
|
252
|
+
[
|
|
253
|
+
{
|
|
254
|
+
"id": "root",
|
|
255
|
+
"component": "Alert",
|
|
256
|
+
"pattern": "dunning",
|
|
257
|
+
"variant": "danger",
|
|
258
|
+
"amount": 24.5,
|
|
259
|
+
"currency": "USD",
|
|
260
|
+
"dueAt": "2026-05-20T00:00:00Z",
|
|
261
|
+
"cardLast4": "4242",
|
|
262
|
+
"reason": "declined",
|
|
263
|
+
"children": ["btn-update", "btn-retry"]
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
"id": "btn-update",
|
|
267
|
+
"component": "Button",
|
|
268
|
+
"text": "Update payment method",
|
|
269
|
+
"variant": "primary",
|
|
270
|
+
"slot": "actions"
|
|
271
|
+
},
|
|
272
|
+
{
|
|
273
|
+
"id": "btn-retry",
|
|
274
|
+
"component": "Button",
|
|
275
|
+
"text": "Retry charge",
|
|
276
|
+
"variant": "outline",
|
|
277
|
+
"slot": "actions"
|
|
278
|
+
}
|
|
279
|
+
]
|
|
167
280
|
keywords:
|
|
168
281
|
- alert
|
|
169
282
|
- inbox
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Edit this file; run `npm run build:components` to regenerate a2ui.json.
|
|
2
2
|
#
|
|
3
3
|
# §176 (v0.5.5): authored to close the §175 baseline-orphan class. The
|
|
4
|
-
# component already existed as a sibling class in the parent's class.js
|
|
4
|
+
# component already existed as a sibling class in the parent's avatar.class.js
|
|
5
5
|
# + was registered alongside the parent (e.g. UIList + UIListItem both
|
|
6
|
-
# from list/class.js). The catalog just lacked its own entry. With the
|
|
6
|
+
# from list/list.class.js). The catalog just lacked its own entry. With the
|
|
7
7
|
# §172 sibling-yaml scanner, this file gets picked up next to the parent
|
|
8
8
|
# yaml.
|
|
9
9
|
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
12
|
import { defineIfFree } from '../../core/register.js';
|
|
13
|
-
import { UIAvatar, UIAvatarGroup } from './class.js';
|
|
13
|
+
import { UIAvatar, UIAvatarGroup } from './avatar.class.js';
|
|
14
14
|
|
|
15
15
|
defineIfFree('avatar-ui', UIAvatar);
|
|
16
16
|
defineIfFree('avatar-group-ui', UIAvatarGroup);
|
|
@@ -31,6 +31,16 @@
|
|
|
31
31
|
"type": "string",
|
|
32
32
|
"default": ""
|
|
33
33
|
},
|
|
34
|
+
"rangeEnd": {
|
|
35
|
+
"description": "End of a date range (ISO YYYY-MM-DD). See `rangeStart` for the full contract.",
|
|
36
|
+
"type": "string",
|
|
37
|
+
"default": ""
|
|
38
|
+
},
|
|
39
|
+
"rangeStart": {
|
|
40
|
+
"description": "Start of a date range (ISO YYYY-MM-DD). When both rangeStart and rangeEnd are set + ordered, day cells strictly between the endpoints get `[data-in-range]` stamped for visual continuity. Used by `<date-range-picker-ui>` which pushes the same from/to onto both calendar panes. Endpoints themselves render via the `value` prop's `[data-selected]` state.",
|
|
41
|
+
"type": "string",
|
|
42
|
+
"default": ""
|
|
43
|
+
},
|
|
34
44
|
"readonly": {
|
|
35
45
|
"description": "Blocks selection but allows month navigation.",
|
|
36
46
|
"type": "boolean",
|
|
@@ -65,6 +65,14 @@ export class UICalendarGrid extends UIElement {
|
|
|
65
65
|
max: { type: String, default: '', reflect: true },
|
|
66
66
|
disabled: { type: Boolean, default: false, reflect: true },
|
|
67
67
|
readonly: { type: Boolean, default: false, reflect: true },
|
|
68
|
+
// Range-aware highlighting — when both rangeStart and rangeEnd are
|
|
69
|
+
// set, day cells whose date falls strictly between them get
|
|
70
|
+
// `[data-in-range]` stamped on them (the endpoints themselves get
|
|
71
|
+
// `[data-selected]` via the `value` prop). Consumers like
|
|
72
|
+
// <date-range-picker-ui> push the same from/to onto both panes so
|
|
73
|
+
// each independently lights up its in-range cells.
|
|
74
|
+
rangeStart: { type: String, default: '', reflect: true, attribute: 'range-start' },
|
|
75
|
+
rangeEnd: { type: String, default: '', reflect: true, attribute: 'range-end' },
|
|
68
76
|
};
|
|
69
77
|
|
|
70
78
|
// No html`` template — we render imperatively via #renderCalendar so we can
|
|
@@ -142,6 +150,11 @@ export class UICalendarGrid extends UIElement {
|
|
|
142
150
|
const selected = parseISO(this.value);
|
|
143
151
|
const minDate = parseISO(this.min);
|
|
144
152
|
const maxDate = parseISO(this.max);
|
|
153
|
+
// Range endpoints — only honor when BOTH are set + valid + ordered.
|
|
154
|
+
const rs = parseISO(this.rangeStart);
|
|
155
|
+
const re = parseISO(this.rangeEnd);
|
|
156
|
+
const rangeFrom = (rs && re && rs <= re) ? rs : null;
|
|
157
|
+
const rangeTo = (rs && re && rs <= re) ? re : null;
|
|
145
158
|
|
|
146
159
|
// Header — Prev / Title / Next
|
|
147
160
|
let h = `<div data-cal-header>
|
|
@@ -174,15 +187,28 @@ export class UICalendarGrid extends UIElement {
|
|
|
174
187
|
const isSelected = selected && sameDay(date, selected);
|
|
175
188
|
const isDisabled = (minDate && date < minDate) || (maxDate && date > maxDate);
|
|
176
189
|
const isFocused = this.#focusedDay === d;
|
|
190
|
+
// In-range: strictly between rangeStart and rangeEnd (endpoints
|
|
191
|
+
// themselves render as `[data-selected]` via the `value` prop;
|
|
192
|
+
// marking them in-range too would double-up the styling).
|
|
193
|
+
const isInRange = !!(rangeFrom && rangeTo
|
|
194
|
+
&& date > rangeFrom && date < rangeTo);
|
|
195
|
+
// Range endpoint flags — let CSS render the start/end cell with
|
|
196
|
+
// half-pill caps so the in-range strip reads as a continuous
|
|
197
|
+
// band when displayed next to the in-range cells.
|
|
198
|
+
const isRangeStart = !!(rangeFrom && sameDay(date, rangeFrom));
|
|
199
|
+
const isRangeEnd = !!(rangeTo && sameDay(date, rangeTo));
|
|
177
200
|
|
|
178
201
|
const attrs = [
|
|
179
202
|
'type="button"',
|
|
180
203
|
'data-cal-day',
|
|
181
204
|
`data-date="${iso}"`,
|
|
182
|
-
isToday
|
|
183
|
-
isSelected
|
|
184
|
-
|
|
185
|
-
|
|
205
|
+
isToday ? 'data-today' : '',
|
|
206
|
+
isSelected ? 'data-selected' : '',
|
|
207
|
+
isInRange ? 'data-in-range' : '',
|
|
208
|
+
isRangeStart ? 'data-range-start' : '',
|
|
209
|
+
isRangeEnd ? 'data-range-end' : '',
|
|
210
|
+
isDisabled ? 'disabled' : '',
|
|
211
|
+
isFocused ? 'data-focused' : '',
|
|
186
212
|
`tabindex="${isFocused ? '0' : '-1'}"`,
|
|
187
213
|
].filter(Boolean).join(' ');
|
|
188
214
|
|
|
@@ -52,6 +52,12 @@
|
|
|
52
52
|
--calendar-grid-day-fg-hover-default: var(--a-fg);
|
|
53
53
|
--calendar-grid-day-bg-selected-default: var(--a-accent);
|
|
54
54
|
--calendar-grid-day-fg-selected-default: var(--a-accent-fg);
|
|
55
|
+
/* In-range cells (strictly between rangeStart and rangeEnd) — muted
|
|
56
|
+
accent strip so the endpoints (full --a-accent fill) read as the
|
|
57
|
+
primary selection while the in-range band reads as secondary
|
|
58
|
+
context. Stylable independently of `selected`. */
|
|
59
|
+
--calendar-grid-day-bg-in-range-default: var(--a-accent-muted);
|
|
60
|
+
--calendar-grid-day-fg-in-range-default: var(--a-fg);
|
|
55
61
|
--calendar-grid-day-fg-outside-default: var(--a-fg-muted);
|
|
56
62
|
--calendar-grid-day-fg-disabled-default: var(--a-ui-text-disabled);
|
|
57
63
|
--calendar-grid-day-today-color-default: var(--a-accent);
|
|
@@ -193,6 +199,20 @@
|
|
|
193
199
|
color: var(--calendar-grid-day-fg-selected, var(--calendar-grid-day-fg-selected-default));
|
|
194
200
|
}
|
|
195
201
|
|
|
202
|
+
/* ── State: in-range ──
|
|
203
|
+
Cells strictly between rangeStart and rangeEnd get the muted accent
|
|
204
|
+
strip. Endpoints themselves render as `[data-selected]` (full accent
|
|
205
|
+
fill); the in-range middle is visually subordinate. `:not([data-selected])`
|
|
206
|
+
guard prevents the muted fill from overriding the endpoint cells in
|
|
207
|
+
consumer code that sets both `value` AND `range-start`/`range-end`. */
|
|
208
|
+
[data-cal-day][data-in-range]:not([data-selected]) {
|
|
209
|
+
background: var(--calendar-grid-day-bg-in-range, var(--calendar-grid-day-bg-in-range-default));
|
|
210
|
+
color: var(--calendar-grid-day-fg-in-range, var(--calendar-grid-day-fg-in-range-default));
|
|
211
|
+
}
|
|
212
|
+
[data-cal-day][data-in-range]:not([data-selected]):not([disabled]):hover {
|
|
213
|
+
background: var(--calendar-grid-day-bg-in-range, var(--calendar-grid-day-bg-in-range-default));
|
|
214
|
+
}
|
|
215
|
+
|
|
196
216
|
/* ── State: today (unselected) ── */
|
|
197
217
|
[data-cal-day][data-today]:not([data-selected]) {
|
|
198
218
|
position: relative;
|
|
@@ -22,6 +22,10 @@ export class UICalendarGrid extends UIElement {
|
|
|
22
22
|
max: string;
|
|
23
23
|
/** Minimum selectable date in ISO format (YYYY-MM-DD). */
|
|
24
24
|
min: string;
|
|
25
|
+
/** End of a date range (ISO YYYY-MM-DD). See `rangeStart` for the full contract. */
|
|
26
|
+
rangeEnd: string;
|
|
27
|
+
/** Start of a date range (ISO YYYY-MM-DD). When both rangeStart and rangeEnd are set + ordered, day cells strictly between the endpoints get `[data-in-range]` stamped for visual continuity. Used by `<date-range-picker-ui>` which pushes the same from/to onto both calendar panes. Endpoints themselves render via the `value` prop's `[data-selected]` state. */
|
|
28
|
+
rangeStart: string;
|
|
25
29
|
/** Blocks selection but allows month navigation. */
|
|
26
30
|
readonly: boolean;
|
|
27
31
|
/** Selected date in ISO format (YYYY-MM-DD). */
|
|
@@ -42,6 +42,26 @@ props:
|
|
|
42
42
|
type: boolean
|
|
43
43
|
default: false
|
|
44
44
|
reflect: true
|
|
45
|
+
rangeStart:
|
|
46
|
+
description: >-
|
|
47
|
+
Start of a date range (ISO YYYY-MM-DD). When both rangeStart and
|
|
48
|
+
rangeEnd are set + ordered, day cells strictly between the
|
|
49
|
+
endpoints get `[data-in-range]` stamped for visual continuity.
|
|
50
|
+
Used by `<date-range-picker-ui>` which pushes the same from/to
|
|
51
|
+
onto both calendar panes. Endpoints themselves render via the
|
|
52
|
+
`value` prop's `[data-selected]` state.
|
|
53
|
+
type: string
|
|
54
|
+
default: ''
|
|
55
|
+
reflect: true
|
|
56
|
+
attribute: range-start
|
|
57
|
+
rangeEnd:
|
|
58
|
+
description: >-
|
|
59
|
+
End of a date range (ISO YYYY-MM-DD). See `rangeStart` for the
|
|
60
|
+
full contract.
|
|
61
|
+
type: string
|
|
62
|
+
default: ''
|
|
63
|
+
reflect: true
|
|
64
|
+
attribute: range-end
|
|
45
65
|
events:
|
|
46
66
|
change:
|
|
47
67
|
description: User selected a date. detail.value is the ISO string.
|
package/components/card/card.js
CHANGED