@adia-ai/web-modules 0.8.40 → 0.8.42
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 +47 -0
- package/README.md +7 -7
- package/agent-admin/admin-roster/admin-roster.a2ui.json +1 -0
- package/agent-admin/admin-roster/admin-roster.css +10 -2
- package/agent-admin/admin-roster/admin-roster.js +70 -22
- package/agent-admin/admin-settings/admin-settings.a2ui.json +1 -0
- package/agent-admin/agent-admin/agent-admin.a2ui.json +1 -0
- package/billing/billing-overview/billing-overview.a2ui.json +10 -1
- package/billing/billing-overview/billing-overview.class.js +142 -73
- package/billing/billing-overview/billing-overview.css +70 -57
- package/billing/billing-overview/billing-overview.yaml +5 -0
- package/billing/invoice-detail/invoice-detail.a2ui.json +9 -4
- package/billing/invoice-detail/invoice-detail.class.js +6 -5
- package/billing/invoice-detail/invoice-detail.yaml +9 -4
- package/billing/invoice-history/invoice-history.a2ui.json +7 -4
- package/billing/invoice-history/invoice-history.class.js +29 -18
- package/billing/invoice-history/invoice-history.css +18 -15
- package/billing/invoice-history/invoice-history.yaml +10 -4
- package/billing/payment-method-form/payment-method-form.a2ui.json +1 -0
- package/billing/payment-method-form/payment-method-form.class.js +3 -3
- package/billing/payment-method-form/payment-method-form.css +4 -4
- package/billing/payment-method-list/payment-method-list.a2ui.json +4 -0
- package/billing/payment-method-list/payment-method-list.class.js +31 -11
- package/billing/payment-method-list/payment-method-list.css +13 -10
- package/billing/payment-method-list/payment-method-list.yaml +3 -0
- package/billing/plan-picker/plan-picker.a2ui.json +6 -0
- package/billing/plan-picker/plan-picker.class.js +70 -22
- package/billing/plan-picker/plan-picker.css +21 -38
- package/billing/plan-picker/plan-picker.yaml +5 -0
- package/chat/chat-composer/chat-composer.a2ui.json +1 -0
- package/chat/chat-empty/chat-empty.a2ui.json +4 -0
- package/chat/chat-empty/chat-empty.yaml +2 -0
- package/chat/chat-header/chat-header.a2ui.json +5 -0
- package/chat/chat-header/chat-header.yaml +3 -0
- package/chat/chat-shell/chat-shell.a2ui.json +4 -0
- package/chat/chat-shell/chat-shell.yaml +2 -0
- package/chat/chat-shell/css/chat-shell.bespoke.css +5 -5
- package/chat/chat-sidebar/chat-sidebar.a2ui.json +5 -1
- package/chat/chat-sidebar/chat-sidebar.d.ts +1 -1
- package/chat/chat-sidebar/chat-sidebar.js +25 -3
- package/chat/chat-sidebar/chat-sidebar.yaml +3 -1
- package/chat/chat-status/chat-status.a2ui.json +4 -0
- package/chat/chat-status/chat-status.yaml +2 -0
- package/chat/chat-thread/chat-thread.a2ui.json +4 -0
- package/chat/chat-thread/chat-thread.yaml +2 -0
- package/dashboard/dashboard-layout/dashboard-layout.a2ui.json +8 -8
- package/dashboard/dashboard-layout/dashboard-layout.css +4 -4
- package/dashboard/dashboard-layout/dashboard-layout.js +10 -9
- package/dashboard/dashboard-layout/dashboard-layout.yaml +19 -7
- package/dashboard/date-range-selector/date-range-selector.a2ui.json +4 -3
- package/dashboard/date-range-selector/date-range-selector.yaml +6 -4
- package/dist/chat/chat-shell.min.css +1 -1
- package/dist/chat/chat-shell.min.js +23 -23
- package/dist/editor/editor-shell.min.js +3 -3
- package/dist/everything.min.js +127 -140
- package/dist/shell/admin-shell.min.css +1 -1
- package/dist/shell/admin-shell.min.js +6 -6
- package/dist/simple/simple-shell.min.js +5 -5
- package/dist/web-modules.min.css +1 -1
- package/dist/web-modules.sheet.js +1 -1
- package/editor/editor-canvas/editor-canvas.a2ui.json +4 -0
- package/editor/editor-canvas/editor-canvas.yaml +2 -0
- package/editor/editor-canvas-empty/editor-canvas-empty.a2ui.json +4 -0
- package/editor/editor-canvas-empty/editor-canvas-empty.yaml +2 -0
- package/editor/editor-canvas-toolbar/editor-canvas-toolbar.a2ui.json +4 -0
- package/editor/editor-canvas-toolbar/editor-canvas-toolbar.yaml +2 -0
- package/editor/editor-shell/editor-shell.a2ui.json +5 -0
- package/editor/editor-shell/editor-shell.yaml +3 -0
- package/editor/editor-sidebar/editor-sidebar.a2ui.json +4 -0
- package/editor/editor-sidebar/editor-sidebar.js +5 -3
- package/editor/editor-sidebar/editor-sidebar.yaml +2 -0
- package/editor/editor-statusbar/editor-statusbar.a2ui.json +4 -0
- package/editor/editor-statusbar/editor-statusbar.yaml +2 -0
- package/editor/editor-toolbar/editor-toolbar.a2ui.json +4 -0
- package/editor/editor-toolbar/editor-toolbar.yaml +2 -0
- package/feedback/confirm-dialog/confirm-dialog.a2ui.json +1 -0
- package/form/form-popover/form-popover.a2ui.json +1 -0
- package/onboarding/onboarding-checklist/onboarding-checklist.a2ui.json +2 -1
- package/onboarding/onboarding-checklist/onboarding-checklist.js +2 -2
- package/onboarding/onboarding-checklist/onboarding-checklist.yaml +1 -1
- package/package.json +6 -6
- package/runtime/a2ui-root/a2ui-root.a2ui.json +6 -5
- package/runtime/a2ui-root/a2ui-root.css +75 -0
- package/runtime/a2ui-root/a2ui-root.js +118 -10
- package/runtime/a2ui-root/a2ui-root.yaml +7 -2
- package/runtime/gen-root/gen-root.a2ui.json +6 -5
- package/runtime/gen-root/gen-root.yaml +10 -2
- package/settings/integrations-page/integrations-page.a2ui.json +3 -2
- package/settings/integrations-page/integrations-page.js +8 -8
- package/settings/integrations-page/integrations-page.yaml +2 -2
- package/settings/notification-preferences/notification-preferences.a2ui.json +1 -0
- package/shell/admin-command/admin-command.a2ui.json +5 -1
- package/shell/admin-command/admin-command.yaml +3 -1
- package/shell/admin-content/admin-content.a2ui.json +4 -0
- package/shell/admin-content/admin-content.yaml +2 -0
- package/shell/admin-entity-item/admin-entity-item.a2ui.json +1 -0
- package/shell/admin-page/admin-page.a2ui.json +5 -0
- package/shell/admin-page/admin-page.yaml +3 -0
- package/shell/admin-page-body/admin-page-body.a2ui.json +4 -0
- package/shell/admin-page-body/admin-page-body.yaml +2 -0
- package/shell/admin-page-footer/admin-page-footer.a2ui.json +4 -0
- package/shell/admin-page-footer/admin-page-footer.yaml +2 -0
- package/shell/admin-page-header/admin-page-header.a2ui.json +4 -0
- package/shell/admin-page-header/admin-page-header.yaml +2 -0
- package/shell/admin-scroll/admin-scroll.a2ui.json +4 -0
- package/shell/admin-scroll/admin-scroll.yaml +2 -0
- package/shell/admin-shell/admin-shell.a2ui.json +8 -4
- package/shell/admin-shell/admin-shell.d.ts +1 -1
- package/shell/admin-shell/admin-shell.yaml +5 -3
- package/shell/admin-shell/css/admin-shell.bespoke.css +5 -5
- package/shell/admin-shell/css/admin-shell.helpers.css +8 -3
- package/shell/admin-shell/css/admin-shell.sidebar.css +6 -6
- package/shell/admin-sidebar/admin-sidebar.a2ui.json +5 -1
- package/shell/admin-sidebar/admin-sidebar.d.ts +1 -1
- package/shell/admin-sidebar/admin-sidebar.js +31 -9
- package/shell/admin-sidebar/admin-sidebar.yaml +3 -1
- package/shell/admin-statusbar/admin-statusbar.a2ui.json +6 -0
- package/shell/admin-statusbar/admin-statusbar.yaml +4 -0
- package/shell/admin-topbar/admin-topbar.a2ui.json +6 -0
- package/shell/admin-topbar/admin-topbar.yaml +4 -0
- package/shell/embed-shell/embed-shell.a2ui.json +1 -0
- package/simple/simple-content/simple-content.a2ui.json +4 -0
- package/simple/simple-content/simple-content.yaml +2 -0
- package/simple/simple-hero/simple-hero.a2ui.json +4 -0
- package/simple/simple-hero/simple-hero.yaml +2 -0
- package/simple/simple-shell/simple-shell.a2ui.json +4 -0
- package/simple/simple-shell/simple-shell.yaml +2 -0
- package/theme/theme-panel/theme-panel.a2ui.json +1 -0
|
@@ -19,11 +19,19 @@
|
|
|
19
19
|
* - stat-ui for the KPI strip
|
|
20
20
|
*
|
|
21
21
|
* Architecture (light-DOM, ADR-0033):
|
|
22
|
-
* Stamps a six-region skeleton once on first connect
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Stamps a six-region skeleton once on first connect. Each region is
|
|
23
|
+
* the canonical settings-section grammar from
|
|
24
|
+
* apps/saas/app/billing/billing.contents.html (gh#1519):
|
|
25
|
+
* <section> → <aside> label rail (h3 + p) → <col-ui> content column
|
|
26
|
+
* The regions, in DOM order:
|
|
27
|
+
* [data-header] — current-plan card-ui (title + status tag
|
|
28
|
+
* + slotted actions) in a labeled section
|
|
29
|
+
* [data-kpis] — <grid-ui> of card-ui>section>stat-ui KPI
|
|
30
|
+
* cards + a seats <progress-ui> quota bar
|
|
25
31
|
* [data-dunning] — alert-ui[pattern="dunning"], conditional
|
|
26
|
-
* [data-plan-picker] — plan-picker-ui
|
|
32
|
+
* [data-plan-picker] — plan-picker-ui (cycle-toggle on — the
|
|
33
|
+
* canonical field-ui billing-interval
|
|
34
|
+
* chain), conditional
|
|
27
35
|
* [data-payment-methods] — payment-method-list-ui section
|
|
28
36
|
* [data-invoice-history] — invoice-history-ui section
|
|
29
37
|
* [data-empty] — default empty-state branch
|
|
@@ -138,6 +146,7 @@ export class UIBillingOverview extends UIElement {
|
|
|
138
146
|
#kpisHost = null;
|
|
139
147
|
#kpiSpend = null;
|
|
140
148
|
#kpiSeats = null;
|
|
149
|
+
#kpiSeatsQuota = null;
|
|
141
150
|
#kpiInvoice = null;
|
|
142
151
|
|
|
143
152
|
// Dunning banner
|
|
@@ -148,6 +157,7 @@ export class UIBillingOverview extends UIElement {
|
|
|
148
157
|
#planPickerHost = null;
|
|
149
158
|
#planPickerHeading = null;
|
|
150
159
|
#planPicker = null;
|
|
160
|
+
#forwardedCycle = '';
|
|
151
161
|
|
|
152
162
|
// Payment-methods section
|
|
153
163
|
#paymentMethodsHost = null;
|
|
@@ -322,15 +332,43 @@ export class UIBillingOverview extends UIElement {
|
|
|
322
332
|
for (const n of nodes) target.appendChild(n);
|
|
323
333
|
}
|
|
324
334
|
|
|
335
|
+
/**
|
|
336
|
+
* Stamp one region in the canonical settings-section grammar
|
|
337
|
+
* (apps/saas/app/billing/billing.contents.html): a <section> whose
|
|
338
|
+
* children are an <aside> label rail (h3 + p) and a <col-ui>
|
|
339
|
+
* content column. Returns [section, contentCol].
|
|
340
|
+
*/
|
|
341
|
+
#stampRegion(marker, heading, description) {
|
|
342
|
+
const section = document.createElement('section');
|
|
343
|
+
section.setAttribute(marker, '');
|
|
344
|
+
const aside = document.createElement('aside');
|
|
345
|
+
const h3 = document.createElement('h3');
|
|
346
|
+
h3.setAttribute('data-section-heading', '');
|
|
347
|
+
h3.textContent = heading;
|
|
348
|
+
const p = document.createElement('p');
|
|
349
|
+
p.setAttribute('data-section-description', '');
|
|
350
|
+
p.textContent = description;
|
|
351
|
+
aside.append(h3, p);
|
|
352
|
+
const col = document.createElement('col-ui');
|
|
353
|
+
col.setAttribute('data-region-content', '');
|
|
354
|
+
col.setAttribute('gap', '3');
|
|
355
|
+
section.append(aside, col);
|
|
356
|
+
this.appendChild(section);
|
|
357
|
+
return [section, col];
|
|
358
|
+
}
|
|
359
|
+
|
|
325
360
|
#stamp() {
|
|
326
361
|
this.#headingId = `bo-h-${Math.random().toString(36).slice(2, 8)}`;
|
|
327
362
|
|
|
328
|
-
// ── Header region ──
|
|
329
|
-
//
|
|
330
|
-
//
|
|
331
|
-
|
|
363
|
+
// ── Header region ── canonical "Current plan" section: aside rail +
|
|
364
|
+
// col-ui column holding the card-ui plan card (billing.contents.html
|
|
365
|
+
// lines 26-62).
|
|
366
|
+
const [headerSection, headerCol] = this.#stampRegion(
|
|
367
|
+
'data-header', 'Current plan', 'Your active subscription and billing interval.',
|
|
368
|
+
);
|
|
369
|
+
|
|
332
370
|
const headerCard = document.createElement('card-ui');
|
|
333
|
-
headerCard.setAttribute('data-
|
|
371
|
+
headerCard.setAttribute('data-plan-card', '');
|
|
334
372
|
|
|
335
373
|
const header = document.createElement('header');
|
|
336
374
|
|
|
@@ -355,11 +393,13 @@ export class UIBillingOverview extends UIElement {
|
|
|
355
393
|
statusBadge.setAttribute('size', 'md');
|
|
356
394
|
headerHeadingSpan.appendChild(statusBadge);
|
|
357
395
|
|
|
358
|
-
// Description slot — plan price/cycle
|
|
396
|
+
// Description slot — plan price/cycle meta as a row-ui cluster.
|
|
359
397
|
const headerDescriptionSpan = document.createElement('span');
|
|
360
398
|
headerDescriptionSpan.setAttribute('slot', 'description');
|
|
361
|
-
const subtitle = document.createElement('
|
|
399
|
+
const subtitle = document.createElement('row-ui');
|
|
362
400
|
subtitle.setAttribute('data-billing-plan-meta', '');
|
|
401
|
+
subtitle.setAttribute('gap', '3');
|
|
402
|
+
subtitle.setAttribute('wrap', '');
|
|
363
403
|
headerDescriptionSpan.appendChild(subtitle);
|
|
364
404
|
|
|
365
405
|
// Action slot — change-plan + consumer-supplied actions.
|
|
@@ -371,9 +411,9 @@ export class UIBillingOverview extends UIElement {
|
|
|
371
411
|
|
|
372
412
|
header.append(headerIconSpan, headerHeadingSpan, headerDescriptionSpan, headerActionSpan);
|
|
373
413
|
headerCard.appendChild(header);
|
|
374
|
-
|
|
414
|
+
headerCol.appendChild(headerCard);
|
|
375
415
|
|
|
376
|
-
this.#headerHost =
|
|
416
|
+
this.#headerHost = headerSection;
|
|
377
417
|
this.#headerTitle = title;
|
|
378
418
|
this.#headerSubtitle = subtitle;
|
|
379
419
|
this.#headerStatus = statusBadge;
|
|
@@ -382,16 +422,23 @@ export class UIBillingOverview extends UIElement {
|
|
|
382
422
|
// Absorb consumer [slot="header-actions"] children.
|
|
383
423
|
this.#absorbSlottedChildren('header-actions', headerActions);
|
|
384
424
|
|
|
385
|
-
// ── KPI strip ──
|
|
386
|
-
//
|
|
387
|
-
//
|
|
388
|
-
//
|
|
389
|
-
const
|
|
390
|
-
|
|
425
|
+
// ── KPI strip ── canonical "Usage this cycle" section: a grid-ui of
|
|
426
|
+
// card-ui>section>stat-ui KPI cards (canonical stats grammar,
|
|
427
|
+
// billing.contents.html change-plan drawer) plus a seats
|
|
428
|
+
// progress-ui quota bar (canonical usage grammar, lines 78-83).
|
|
429
|
+
const [kpisSection, kpisCol] = this.#stampRegion(
|
|
430
|
+
'data-kpis', 'Usage this cycle', 'Spend, seats, and your next invoice.',
|
|
431
|
+
);
|
|
432
|
+
|
|
433
|
+
const kpiGrid = document.createElement('grid-ui');
|
|
434
|
+
kpiGrid.setAttribute('data-kpi-grid', '');
|
|
435
|
+
kpiGrid.setAttribute('columns', '3');
|
|
436
|
+
kpiGrid.setAttribute('gap', '3');
|
|
437
|
+
kpisCol.appendChild(kpiGrid);
|
|
391
438
|
|
|
392
439
|
/**
|
|
393
440
|
* Helper: wrap a stat-ui in <card-ui><section> per canonical KPI pattern.
|
|
394
|
-
* @returns {[HTMLElement, HTMLElement]} [cardWrapper, statElement]
|
|
441
|
+
* @returns {[HTMLElement, HTMLElement, HTMLElement]} [cardWrapper, statElement, cardSection]
|
|
395
442
|
*/
|
|
396
443
|
const makeKpiCard = (kpiId, label, icon) => {
|
|
397
444
|
const card = document.createElement('card-ui');
|
|
@@ -404,91 +451,92 @@ export class UIBillingOverview extends UIElement {
|
|
|
404
451
|
stat.setAttribute('icon', icon);
|
|
405
452
|
section.appendChild(stat);
|
|
406
453
|
card.appendChild(section);
|
|
407
|
-
return [card, stat];
|
|
454
|
+
return [card, stat, section];
|
|
408
455
|
};
|
|
409
456
|
|
|
410
457
|
const [kpiSpendCard, kpiSpend] = makeKpiCard('spend', 'Current month', 'credit-card');
|
|
411
|
-
const [kpiSeatsCard, kpiSeats] = makeKpiCard('seats', 'Seats', 'users-three');
|
|
458
|
+
const [kpiSeatsCard, kpiSeats, kpiSeatsSection] = makeKpiCard('seats', 'Seats', 'users-three');
|
|
412
459
|
const [kpiInvoiceCard, kpiInvoice] = makeKpiCard('next-invoice', 'Next invoice', 'calendar');
|
|
413
460
|
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
461
|
+
// Seats quota bar — progress-ui[label][meta] per the canonical usage
|
|
462
|
+
// section; hidden until account.seats carries a usable used/total.
|
|
463
|
+
const seatsQuota = document.createElement('progress-ui');
|
|
464
|
+
seatsQuota.setAttribute('data-seats-quota', '');
|
|
465
|
+
seatsQuota.setAttribute('label', 'Seats used');
|
|
466
|
+
seatsQuota.setAttribute('hidden', '');
|
|
467
|
+
kpiSeatsSection.appendChild(seatsQuota);
|
|
468
|
+
|
|
469
|
+
kpiGrid.append(kpiSpendCard, kpiSeatsCard, kpiInvoiceCard);
|
|
470
|
+
this.#kpisHost = kpisSection;
|
|
417
471
|
this.#kpiSpend = kpiSpend;
|
|
418
472
|
this.#kpiSeats = kpiSeats;
|
|
473
|
+
this.#kpiSeatsQuota = seatsQuota;
|
|
419
474
|
this.#kpiInvoice = kpiInvoice;
|
|
420
475
|
|
|
421
|
-
// ── Dunning banner ── alert-ui[pattern="dunning"], conditional
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
476
|
+
// ── Dunning banner ── alert-ui[pattern="dunning"], conditional; the
|
|
477
|
+
// whole labeled section hides for non-past-due accounts.
|
|
478
|
+
const [dunningSection, dunningCol] = this.#stampRegion(
|
|
479
|
+
'data-dunning', 'Payment issue', 'Action needed to keep your subscription active.',
|
|
480
|
+
);
|
|
481
|
+
dunningSection.setAttribute('hidden', '');
|
|
425
482
|
const dunningAlert = document.createElement('alert-ui');
|
|
426
483
|
dunningAlert.setAttribute('pattern', 'dunning');
|
|
427
484
|
dunningAlert.setAttribute('variant', 'danger');
|
|
428
|
-
|
|
429
|
-
this
|
|
430
|
-
this.#dunningHost = dunningHost;
|
|
485
|
+
dunningCol.appendChild(dunningAlert);
|
|
486
|
+
this.#dunningHost = dunningSection;
|
|
431
487
|
this.#dunningAlert = dunningAlert;
|
|
432
488
|
|
|
433
|
-
// ── Plan-picker section ── conditional on [variant=full].
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
planPicker.setAttribute('data-billing-plan-picker', '');
|
|
441
|
-
planPicker.setAttribute('name', 'billing-overview-plan');
|
|
442
|
-
planPickerHost.append(planPickerHeading, planPicker);
|
|
443
|
-
|
|
444
|
-
// Optional before-plan-picker slot anchor sits before the plan picker
|
|
445
|
-
// section card. We absorb consumer-authored content into planPickerHost
|
|
446
|
-
// ahead of the heading.
|
|
447
|
-
this.appendChild(planPickerHost);
|
|
448
|
-
this.#planPickerHost = planPickerHost;
|
|
449
|
-
this.#planPickerHeading = planPickerHeading;
|
|
450
|
-
this.#planPicker = planPicker;
|
|
489
|
+
// ── Plan-picker section ── conditional on [variant=full]. The picker
|
|
490
|
+
// runs with [cycle-toggle] so its field-ui("Billing interval") +
|
|
491
|
+
// segmented-ui chain — the canonical current-plan region's interval
|
|
492
|
+
// switcher — renders inline.
|
|
493
|
+
const [planPickerSection, planPickerCol] = this.#stampRegion(
|
|
494
|
+
'data-plan-picker', 'Plan', 'Compare plans and switch anytime.',
|
|
495
|
+
);
|
|
451
496
|
|
|
452
|
-
// Absorb before-plan-picker slot content
|
|
453
|
-
// ahead of the plan picker.
|
|
497
|
+
// Absorb before-plan-picker slot content ahead of the plan picker.
|
|
454
498
|
const beforePlanPicker = document.createElement('div');
|
|
455
499
|
beforePlanPicker.setAttribute('data-before-plan-picker', '');
|
|
456
|
-
|
|
500
|
+
planPickerCol.appendChild(beforePlanPicker);
|
|
457
501
|
this.#absorbSlottedChildren('before-plan-picker', beforePlanPicker);
|
|
458
502
|
|
|
503
|
+
const planPicker = document.createElement('plan-picker-ui');
|
|
504
|
+
planPicker.setAttribute('data-billing-plan-picker', '');
|
|
505
|
+
planPicker.setAttribute('name', 'billing-overview-plan');
|
|
506
|
+
planPicker.setAttribute('cycle-toggle', '');
|
|
507
|
+
planPickerCol.appendChild(planPicker);
|
|
508
|
+
|
|
509
|
+
this.#planPickerHost = planPickerSection;
|
|
510
|
+
this.#planPickerHeading = planPickerSection.querySelector('[data-section-heading]');
|
|
511
|
+
this.#planPicker = planPicker;
|
|
512
|
+
|
|
459
513
|
// ── Payment-methods section ──
|
|
460
|
-
const
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
paymentMethodsHeading.setAttribute('data-section-heading', '');
|
|
464
|
-
paymentMethodsHeading.textContent = 'Payment methods';
|
|
514
|
+
const [paymentMethodsSection, paymentMethodsCol] = this.#stampRegion(
|
|
515
|
+
'data-payment-methods', 'Payment methods', 'Cards and wallets on file for recurring charges.',
|
|
516
|
+
);
|
|
465
517
|
const paymentMethods = document.createElement('payment-method-list-ui');
|
|
466
518
|
paymentMethods.setAttribute('data-billing-payment-methods', '');
|
|
467
519
|
paymentMethods.setAttribute('name', 'billing-overview-payment-method');
|
|
468
|
-
|
|
469
|
-
this
|
|
470
|
-
this.#
|
|
471
|
-
this.#paymentMethodsHeading = paymentMethodsHeading;
|
|
520
|
+
paymentMethodsCol.appendChild(paymentMethods);
|
|
521
|
+
this.#paymentMethodsHost = paymentMethodsSection;
|
|
522
|
+
this.#paymentMethodsHeading = paymentMethodsSection.querySelector('[data-section-heading]');
|
|
472
523
|
this.#paymentMethods = paymentMethods;
|
|
473
524
|
|
|
474
525
|
// ── Invoice-history section ──
|
|
475
|
-
const
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
invoiceHistoryHeading.setAttribute('data-section-heading', '');
|
|
479
|
-
invoiceHistoryHeading.textContent = 'Invoice history';
|
|
526
|
+
const [invoiceHistorySection, invoiceHistoryCol] = this.#stampRegion(
|
|
527
|
+
'data-invoice-history', 'Invoice history', 'Download past invoices for accounting.',
|
|
528
|
+
);
|
|
480
529
|
const invoiceHistory = document.createElement('invoice-history-ui');
|
|
481
530
|
invoiceHistory.setAttribute('data-billing-invoice-history', '');
|
|
482
|
-
|
|
483
|
-
this
|
|
484
|
-
this.#
|
|
485
|
-
this.#invoiceHistoryHeading = invoiceHistoryHeading;
|
|
531
|
+
invoiceHistoryCol.appendChild(invoiceHistory);
|
|
532
|
+
this.#invoiceHistoryHost = invoiceHistorySection;
|
|
533
|
+
this.#invoiceHistoryHeading = invoiceHistorySection.querySelector('[data-section-heading]');
|
|
486
534
|
this.#invoiceHistory = invoiceHistory;
|
|
487
535
|
|
|
488
536
|
// After-invoice-history slot anchor.
|
|
489
537
|
const afterInvoiceHistory = document.createElement('div');
|
|
490
538
|
afterInvoiceHistory.setAttribute('data-after-invoice-history', '');
|
|
491
|
-
|
|
539
|
+
invoiceHistoryCol.appendChild(afterInvoiceHistory);
|
|
492
540
|
this.#absorbSlottedChildren('after-invoice-history', afterInvoiceHistory);
|
|
493
541
|
|
|
494
542
|
// ── Empty state ──
|
|
@@ -582,7 +630,8 @@ export class UIBillingOverview extends UIElement {
|
|
|
582
630
|
this.#kpiSpend.setAttribute('value', '—');
|
|
583
631
|
}
|
|
584
632
|
|
|
585
|
-
// KPI 2 — seats (used / total)
|
|
633
|
+
// KPI 2 — seats (used / total) + the seats quota bar (canonical
|
|
634
|
+
// usage-section progress-ui[label][meta] grammar).
|
|
586
635
|
if (account?.seats && Number.isFinite(account.seats.used)) {
|
|
587
636
|
const used = account.seats.used;
|
|
588
637
|
const total = Number.isFinite(account.seats.total) ? account.seats.total : null;
|
|
@@ -590,8 +639,19 @@ export class UIBillingOverview extends UIElement {
|
|
|
590
639
|
'value',
|
|
591
640
|
total != null ? `${used} / ${total}` : String(used),
|
|
592
641
|
);
|
|
642
|
+
if (this.#kpiSeatsQuota) {
|
|
643
|
+
if (total != null && total > 0) {
|
|
644
|
+
const pct = Math.max(0, Math.min(100, Math.round((used / total) * 100)));
|
|
645
|
+
this.#kpiSeatsQuota.setAttribute('value', String(pct));
|
|
646
|
+
this.#kpiSeatsQuota.setAttribute('meta', `${used} / ${total}`);
|
|
647
|
+
this.#kpiSeatsQuota.removeAttribute('hidden');
|
|
648
|
+
} else {
|
|
649
|
+
this.#kpiSeatsQuota.setAttribute('hidden', '');
|
|
650
|
+
}
|
|
651
|
+
}
|
|
593
652
|
} else {
|
|
594
653
|
this.#kpiSeats.setAttribute('value', '—');
|
|
654
|
+
if (this.#kpiSeatsQuota) this.#kpiSeatsQuota.setAttribute('hidden', '');
|
|
595
655
|
}
|
|
596
656
|
|
|
597
657
|
// KPI 3 — next invoice date.
|
|
@@ -683,6 +743,15 @@ export class UIBillingOverview extends UIElement {
|
|
|
683
743
|
this.#planPicker.setAttribute('current', String(account.plan.id));
|
|
684
744
|
}
|
|
685
745
|
|
|
746
|
+
// Seed the picker's billing cycle from account.billingCycle — only
|
|
747
|
+
// when the ACCOUNT's cycle changes, so a user toggle inside the
|
|
748
|
+
// picker isn't clobbered by unrelated re-renders (loading flips).
|
|
749
|
+
const cycle = account?.billingCycle === 'year' ? 'annual' : 'monthly';
|
|
750
|
+
if (this.#forwardedCycle !== cycle) {
|
|
751
|
+
this.#forwardedCycle = cycle;
|
|
752
|
+
this.#planPicker.setAttribute('cycle', cycle);
|
|
753
|
+
}
|
|
754
|
+
|
|
686
755
|
if (this.loading) this.#planPicker.setAttribute('loading', '');
|
|
687
756
|
else this.#planPicker.removeAttribute('loading');
|
|
688
757
|
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
/* ═══════════════════════════════════════════════════════════════
|
|
2
2
|
<billing-overview-ui> — Module-tier billing dashboard composite.
|
|
3
3
|
|
|
4
|
-
Stamps a stacked column of dashboard regions
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
Stamps a stacked column of dashboard regions, each in the canonical
|
|
5
|
+
settings-section grammar from apps/saas/app/billing/billing.contents.html
|
|
6
|
+
(gh#1519): <section> → <aside> label rail (h3 + p) → <col-ui> content.
|
|
7
|
+
[data-header] current-plan card (title + status + actions)
|
|
8
|
+
[data-kpis] grid-ui of card>section>stat KPI cards +
|
|
9
|
+
seats progress-ui quota bar
|
|
7
10
|
[data-dunning] alert-ui[pattern=dunning], conditional
|
|
8
11
|
[data-plan-picker] plan-picker-ui section
|
|
9
12
|
[data-payment-methods] payment-method-list-ui section
|
|
10
13
|
[data-invoice-history] invoice-history-ui section
|
|
11
14
|
[data-empty] default empty-state branch
|
|
12
15
|
|
|
13
|
-
|
|
16
|
+
Layout primitives (col-ui / row-ui / grid-ui) own the stack/row/grid
|
|
17
|
+
geometry; this file styles only the region grid, the aside rail, and
|
|
18
|
+
text chrome. SPEC: docs/specs/implementation-ready/SPEC-004-billing-overview.md
|
|
14
19
|
Two-block @scope pattern per docs/specs/component-token-contract.md.
|
|
15
20
|
Zero raw color values (repo hard rule); rem for sizes ≥ 3px.
|
|
16
21
|
═══════════════════════════════════════════════════════════════ */
|
|
@@ -22,7 +27,9 @@ billing-overview-ui {
|
|
|
22
27
|
--billing-overview-gap: var(--a-space-5);
|
|
23
28
|
--billing-overview-px: var(--a-space-5);
|
|
24
29
|
--billing-overview-py: var(--a-space-5);
|
|
25
|
-
|
|
30
|
+
|
|
31
|
+
--billing-overview-rail-w: 14rem;
|
|
32
|
+
--billing-overview-rail-gap: var(--a-space-4);
|
|
26
33
|
|
|
27
34
|
--billing-overview-header-gap: var(--a-space-3);
|
|
28
35
|
|
|
@@ -33,6 +40,9 @@ billing-overview-ui {
|
|
|
33
40
|
--billing-overview-section-heading-size: var(--a-text-base, 1rem);
|
|
34
41
|
--billing-overview-section-heading-weight: var(--a-weight-semibold, 600);
|
|
35
42
|
|
|
43
|
+
--billing-overview-section-description-fg: var(--a-fg-muted);
|
|
44
|
+
--billing-overview-section-description-size: var(--a-text-sm, 0.875rem);
|
|
45
|
+
|
|
36
46
|
--billing-overview-title-size: var(--a-text-2xl, 1.5rem);
|
|
37
47
|
--billing-overview-title-weight: var(--a-weight-bold, 700);
|
|
38
48
|
|
|
@@ -59,11 +69,46 @@ billing-overview-ui {
|
|
|
59
69
|
container-name: billing-overview;
|
|
60
70
|
}
|
|
61
71
|
|
|
62
|
-
/* ──
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
72
|
+
/* ── Region grammar ── every region section is an <aside> label rail
|
|
73
|
+
beside a <col-ui> content column (the canonical [data-section]
|
|
74
|
+
aside + data-col shape). */
|
|
75
|
+
:scope > section {
|
|
76
|
+
display: grid;
|
|
77
|
+
grid-template-columns: minmax(0, var(--billing-overview-rail-w)) minmax(0, 1fr);
|
|
78
|
+
column-gap: var(--billing-overview-gap);
|
|
79
|
+
row-gap: var(--billing-overview-rail-gap);
|
|
80
|
+
align-items: start;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
:scope > section[hidden] {
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
66
86
|
|
|
87
|
+
:scope > section > aside {
|
|
88
|
+
display: flex;
|
|
89
|
+
flex-direction: column;
|
|
90
|
+
gap: var(--a-space-1);
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
:scope [data-section-heading] {
|
|
94
|
+
margin: 0;
|
|
95
|
+
font-size: var(--billing-overview-section-heading-size);
|
|
96
|
+
font-weight: var(--billing-overview-section-heading-weight);
|
|
97
|
+
color: var(--billing-overview-section-heading-fg);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
:scope [data-section-description] {
|
|
101
|
+
margin: 0;
|
|
102
|
+
font-size: var(--billing-overview-section-description-size);
|
|
103
|
+
color: var(--billing-overview-section-description-fg);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
:scope > section > [data-region-content] {
|
|
107
|
+
min-width: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* ── Header region ── card-ui owns the card layout; we style only the
|
|
111
|
+
inline heading/meta content. */
|
|
67
112
|
:scope > [data-header] [data-billing-plan-name] {
|
|
68
113
|
margin: 0;
|
|
69
114
|
font-size: var(--billing-overview-title-size);
|
|
@@ -72,10 +117,8 @@ billing-overview-ui {
|
|
|
72
117
|
line-height: 1.2;
|
|
73
118
|
}
|
|
74
119
|
|
|
120
|
+
/* Plan meta — a <row-ui wrap>; row-ui owns the flex geometry. */
|
|
75
121
|
:scope > [data-header] [data-billing-plan-meta] {
|
|
76
|
-
display: flex;
|
|
77
|
-
flex-wrap: wrap;
|
|
78
|
-
gap: var(--a-space-3);
|
|
79
122
|
font-size: var(--billing-overview-meta-size);
|
|
80
123
|
color: var(--billing-overview-meta-fg);
|
|
81
124
|
}
|
|
@@ -105,52 +148,27 @@ billing-overview-ui {
|
|
|
105
148
|
display: none;
|
|
106
149
|
}
|
|
107
150
|
|
|
108
|
-
/* ── KPI strip ──
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
:scope > [data-kpis] {
|
|
112
|
-
display: grid;
|
|
151
|
+
/* ── KPI strip ── a <grid-ui data-kpi-grid> of card-ui>section>stat-ui
|
|
152
|
+
cards; forward this composite's column/gap tokens into the grid. */
|
|
153
|
+
:scope grid-ui[data-kpi-grid] {
|
|
113
154
|
grid-template-columns: var(--billing-overview-kpi-columns);
|
|
114
|
-
gap: var(--billing-overview-kpi-gap);
|
|
155
|
+
--grid-gap: var(--billing-overview-kpi-gap);
|
|
115
156
|
}
|
|
116
157
|
|
|
117
|
-
/*
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
:scope > [data-dunning] {
|
|
121
|
-
display: block;
|
|
158
|
+
/* Seats quota bar under the seats stat (canonical usage grammar). */
|
|
159
|
+
:scope [data-seats-quota] {
|
|
160
|
+
margin-block-start: var(--a-space-2);
|
|
122
161
|
}
|
|
123
|
-
|
|
124
|
-
:scope > [data-dunning][hidden] {
|
|
162
|
+
:scope [data-seats-quota][hidden] {
|
|
125
163
|
display: none;
|
|
126
164
|
}
|
|
127
165
|
|
|
128
|
-
/* ──
|
|
129
|
-
:scope
|
|
130
|
-
:scope
|
|
131
|
-
:scope > [data-invoice-history] {
|
|
132
|
-
display: flex;
|
|
133
|
-
flex-direction: column;
|
|
134
|
-
gap: var(--a-space-3);
|
|
135
|
-
background: var(--md-sys-color-neutral-background);
|
|
136
|
-
border: 1px solid var(--md-sys-color-neutral-outline-variant);
|
|
137
|
-
border-radius: var(--billing-overview-section-radius);
|
|
138
|
-
padding: var(--a-space-4);
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
:scope > [data-plan-picker][hidden],
|
|
142
|
-
:scope > [data-payment-methods][hidden],
|
|
143
|
-
:scope > [data-invoice-history][hidden] {
|
|
166
|
+
/* ── Slot anchors ── */
|
|
167
|
+
:scope [data-before-plan-picker]:empty,
|
|
168
|
+
:scope [data-after-invoice-history]:empty {
|
|
144
169
|
display: none;
|
|
145
170
|
}
|
|
146
171
|
|
|
147
|
-
:scope [data-section-heading] {
|
|
148
|
-
margin: 0;
|
|
149
|
-
font-size: var(--billing-overview-section-heading-size);
|
|
150
|
-
font-weight: var(--billing-overview-section-heading-weight);
|
|
151
|
-
color: var(--billing-overview-section-heading-fg);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
172
|
/* ── Variant cascade ── */
|
|
155
173
|
/* compact + enterprise hide the plan-picker section (also gated in JS). */
|
|
156
174
|
:scope[variant="compact"] > [data-plan-picker],
|
|
@@ -158,12 +176,6 @@ billing-overview-ui {
|
|
|
158
176
|
display: none;
|
|
159
177
|
}
|
|
160
178
|
|
|
161
|
-
/* ── Slot anchors ── */
|
|
162
|
-
:scope [data-before-plan-picker]:empty,
|
|
163
|
-
:scope [data-after-invoice-history]:empty {
|
|
164
|
-
display: none;
|
|
165
|
-
}
|
|
166
|
-
|
|
167
179
|
/* ── Empty + loading states ── */
|
|
168
180
|
:scope > [data-empty] {
|
|
169
181
|
display: none;
|
|
@@ -208,12 +220,13 @@ billing-overview-ui {
|
|
|
208
220
|
color: var(--a-danger-strong, var(--a-danger, var(--a-fg-muted)));
|
|
209
221
|
}
|
|
210
222
|
|
|
211
|
-
/* ── Container query —
|
|
223
|
+
/* ── Container query — stack region rails + collapse the KPI grid
|
|
224
|
+
below ~640px ── */
|
|
212
225
|
@container billing-overview (max-width: 40rem) {
|
|
213
|
-
:scope >
|
|
226
|
+
:scope > section {
|
|
214
227
|
grid-template-columns: 1fr;
|
|
215
228
|
}
|
|
216
|
-
:scope
|
|
229
|
+
:scope grid-ui[data-kpi-grid] {
|
|
217
230
|
grid-template-columns: 1fr;
|
|
218
231
|
}
|
|
219
232
|
:scope > [data-header] [data-header-actions] {
|
|
@@ -27,17 +27,21 @@
|
|
|
27
27
|
"default": ""
|
|
28
28
|
},
|
|
29
29
|
"density": {
|
|
30
|
-
"description": "Line-items table row density. `compact` for tightly-packed\ninvoices with many line items;
|
|
30
|
+
"description": "Line-items table row density. `compact` for tightly-packed\ninvoices with many line items; unset (default) for typical\ninvoices. Forwarded to the embedded <table-ui density>.\nConverged onto the global `[density]` Enum·preset vocabulary\n(gh#1335) — `standard` retired (it was never a real state; the\nforwarding logic already treated it as unset) and `spacious`\nadded for parity with the global grammar.\n",
|
|
31
31
|
"type": "string",
|
|
32
32
|
"enum": [
|
|
33
|
+
"",
|
|
33
34
|
"compact",
|
|
34
|
-
"
|
|
35
|
+
"spacious"
|
|
35
36
|
],
|
|
36
|
-
"default": "
|
|
37
|
+
"default": ""
|
|
37
38
|
},
|
|
38
39
|
"invoice": {
|
|
39
40
|
"description": "The invoice record. Source of truth for the rendered page.\nShape: {number, status, issuedAt, dueAt, customer:{name,email},\nremitTo?:{name,address?}, lines:[{description,qty,unitAmount,\namount}], subtotal, tax, discount?, total, currency,\nnotes?:string}. Null + no data-stream-src renders the empty\nstate.\n",
|
|
40
|
-
"type":
|
|
41
|
+
"type": [
|
|
42
|
+
"object",
|
|
43
|
+
"null"
|
|
44
|
+
],
|
|
41
45
|
"default": null
|
|
42
46
|
},
|
|
43
47
|
"loading": {
|
|
@@ -167,6 +171,7 @@
|
|
|
167
171
|
"void"
|
|
168
172
|
],
|
|
169
173
|
"name": "UIInvoiceDetail",
|
|
174
|
+
"parts": {},
|
|
170
175
|
"related": [
|
|
171
176
|
"Card",
|
|
172
177
|
"Table",
|
|
@@ -92,13 +92,14 @@ function formatDate(iso, locale) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
/**
|
|
95
|
-
* Translate invoice-detail-ui's own `density`
|
|
96
|
-
*
|
|
97
|
-
*
|
|
95
|
+
* Translate invoice-detail-ui's own `density` onto table-ui's global
|
|
96
|
+
* [density] grammar (ADR-0054). gh#1335 — the vocabulary now IS the
|
|
97
|
+
* global one (compact/spacious/unset), so this is an identity passthrough
|
|
98
|
+
* for a real value; "" (or anything unrecognized) is the absent attribute.
|
|
98
99
|
* Returns null for "no attribute".
|
|
99
100
|
*/
|
|
100
101
|
function mapDensity(density) {
|
|
101
|
-
return density === 'compact'
|
|
102
|
+
return density === 'compact' || density === 'spacious' ? density : null;
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
export class UIInvoiceDetail extends UIElement {
|
|
@@ -108,7 +109,7 @@ export class UIInvoiceDetail extends UIElement {
|
|
|
108
109
|
invoice: { type: Object, default: null },
|
|
109
110
|
status: { type: String, default: 'draft', reflect: true },
|
|
110
111
|
currency: { type: String, default: 'USD', reflect: true },
|
|
111
|
-
density: { type: String, default: '
|
|
112
|
+
density: { type: String, default: '', reflect: true },
|
|
112
113
|
loading: { type: Boolean, default: false, reflect: true },
|
|
113
114
|
printable: { type: Boolean, default: true, reflect: true },
|
|
114
115
|
locale: { type: String, default: '' },
|
|
@@ -86,13 +86,18 @@ props:
|
|
|
86
86
|
density:
|
|
87
87
|
description: |
|
|
88
88
|
Line-items table row density. `compact` for tightly-packed
|
|
89
|
-
invoices with many line items;
|
|
90
|
-
Forwarded to the embedded <table-ui density>.
|
|
89
|
+
invoices with many line items; unset (default) for typical
|
|
90
|
+
invoices. Forwarded to the embedded <table-ui density>.
|
|
91
|
+
Converged onto the global `[density]` Enum·preset vocabulary
|
|
92
|
+
(gh#1335) — `standard` retired (it was never a real state; the
|
|
93
|
+
forwarding logic already treated it as unset) and `spacious`
|
|
94
|
+
added for parity with the global grammar.
|
|
91
95
|
type: string
|
|
92
|
-
default: "
|
|
96
|
+
default: ""
|
|
93
97
|
enum:
|
|
98
|
+
- ""
|
|
94
99
|
- compact
|
|
95
|
-
-
|
|
100
|
+
- spacious
|
|
96
101
|
reflect: true
|
|
97
102
|
|
|
98
103
|
loading:
|