@adia-ai/web-components 0.6.47 → 0.6.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/components/badge/badge.d.ts +14 -0
  3. package/components/button/button.a2ui.json +1 -4
  4. package/components/button/button.d.ts +1 -1
  5. package/components/button/button.yaml +0 -3
  6. package/components/calendar-grid/calendar-grid.a2ui.json +5 -0
  7. package/components/calendar-grid/calendar-grid.class.js +8 -1
  8. package/components/calendar-grid/calendar-grid.css +20 -11
  9. package/components/calendar-grid/calendar-grid.d.ts +2 -0
  10. package/components/calendar-grid/calendar-grid.yaml +8 -0
  11. package/components/calendar-picker/calendar-picker.css +19 -10
  12. package/components/card/card.a2ui.json +2 -5
  13. package/components/card/card.css +3 -1
  14. package/components/card/card.d.ts +2 -2
  15. package/components/card/card.yaml +2 -5
  16. package/components/date-range-picker/date-range-picker.class.js +9 -0
  17. package/components/date-range-picker/date-range-picker.css +10 -1
  18. package/components/field/field.test.js +7 -2
  19. package/components/heatmap/heatmap.a2ui.json +2 -0
  20. package/components/heatmap/heatmap.d.ts +1 -1
  21. package/components/heatmap/heatmap.yaml +2 -0
  22. package/components/index.js +1 -0
  23. package/components/preview/preview.a2ui.json +93 -0
  24. package/components/preview/preview.class.js +178 -0
  25. package/components/preview/preview.css +176 -0
  26. package/components/preview/preview.d.ts +24 -0
  27. package/components/preview/preview.js +22 -0
  28. package/components/preview/preview.yaml +100 -0
  29. package/components/progress/progress.a2ui.json +2 -7
  30. package/components/progress/progress.d.ts +2 -2
  31. package/components/progress/progress.yaml +3 -8
  32. package/components/progress-row/progress-row.a2ui.json +1 -3
  33. package/components/progress-row/progress-row.d.ts +1 -1
  34. package/components/progress-row/progress-row.yaml +0 -2
  35. package/components/select/select.a2ui.json +2 -4
  36. package/components/select/select.yaml +2 -2
  37. package/components/tabs/tabs.a2ui.json +1 -4
  38. package/components/tabs/tabs.d.ts +2 -2
  39. package/components/tabs/tabs.yaml +2 -2
  40. package/core/anchor.js +5 -1
  41. package/dist/web-components.min.css +1 -1
  42. package/dist/web-components.min.js +75 -73
  43. package/index.css +6 -6
  44. package/package.json +1 -1
  45. package/styles/README.md +71 -36
  46. package/styles/api/layout.css +19 -0
  47. package/styles/api/sizing.css +225 -0
  48. package/styles/api/text.css +106 -0
  49. package/styles/colors/semantics/aliases.css +32 -0
  50. package/styles/colors/semantics/buckets.css +64 -0
  51. package/styles/colors/semantics/core.css +317 -0
  52. package/styles/colors/semantics/data-viz.css +129 -0
  53. package/styles/colors/semantics/features.css +114 -0
  54. package/styles/colors/semantics.css +10 -619
  55. package/styles/components.css +1 -0
  56. package/styles/foundation/elevation.css +29 -0
  57. package/styles/foundation/index.css +11 -0
  58. package/styles/foundation/motion.css +10 -0
  59. package/styles/foundation/radius.css +27 -0
  60. package/styles/foundation/size.css +33 -0
  61. package/styles/foundation/space.css +47 -0
  62. package/styles/index.css +14 -0
  63. package/styles/resets.css +17 -25
  64. package/styles/tokens.css +16 -384
  65. package/styles/type/elements.css +225 -0
  66. package/styles/type/roles.css +419 -0
  67. package/styles/type/scale.css +89 -0
  68. package/styles/typography.css +11 -809
package/CHANGELOG.md CHANGED
@@ -1,5 +1,78 @@
1
1
  # Changelog — @adia-ai/web-components
2
2
 
3
+ ## [0.6.49] — 2026-05-30
4
+
5
+ ### Changed — card-ui header slot sweep + `nav-group-ui` fixes (demos)
6
+
7
+ - **`patterns/*` + catalog demo HTML** — card-ui header anatomy swept to the canonical `<header>` slot grammar across admin-dashboard + 5 catalog patterns; `nav-group-ui` `label=` → `text=` + icon fixes. Demo/corpus-facing; absorbed into the chunk corpus regen.
8
+ - **31 module demos** — `<!-- design-plan -->` blocks retrofitted across the composite-demo-protocol campaign (Phase 1+3 artifacts embedded).
9
+
10
+ ### Maintenance
11
+
12
+ - **`dist/web-components.min.js` + `dist/icons-manifest.js`** — bundle rebuild reflecting the calendar-grid `month` prop + date-range-picker class changes.
13
+
14
+ ### Fixed — `<date-range-picker>` showed the same month in both panes
15
+
16
+ - **`components/calendar-grid/calendar-grid.{class.js,yaml}`** — new `month`
17
+ attribute (`YYYY-MM`): sets the displayed month when no `value` is selected, so
18
+ a consumer can show a specific month independent of selection. A selected value
19
+ always takes precedence.
20
+ - **`components/date-range-picker/date-range-picker.class.js`** — the end pane now
21
+ defaults to **one month after** the start pane (via the new `month` hint), so a
22
+ fresh range picker shows two consecutive months (e.g. May + June) instead of the
23
+ current month twice. A selected `to` date still drives its own pane. Propagates
24
+ to `<date-range-selector>` (embeds the picker).
25
+
26
+ ### Fixed — `drop-target` demo card-structure violation
27
+
28
+ - **`traits/drop-target/drop-target.examples.html`** — the 4 `<card-ui>` drop
29
+ surfaces held `<text-ui>` / `<col-ui>` directly (bypassing the card body slot),
30
+ failing `check:card-structure` (a `check`-chain gate). Wrapped each in
31
+ `<section bleed style="display:grid;place-items:center">` — clears the gate while
32
+ keeping the centered drop-zone appearance. `audit:card-structure` now clean.
33
+
34
+ ## [0.6.48] — 2026-05-29
35
+
36
+ ### Demos — library-wide consolidation sweep (HTML-first)
37
+
38
+ - **`components/**/*.examples.html` + `traits/**/*.examples.html`** — Usage-section consolidation across 83 components + 45 traits: every example now shows its own auto-stamped HTML, so the standalone Usage cheat-sheet was redundant. Per-page consolidations (text, card, drawer) + implemented-matrix depth fills. See the root CHANGELOG for the full campaign.
39
+
40
+ ### Changed — foundation styles reorganized by dimension × layer (ADR-0035)
41
+
42
+ - **`styles/`** — the foundation token surface is now organized by **dimension × layer**. `tokens.css`, `typography.css`, and `colors/semantics.css` remain as **compat barrels** at their published paths (the `@adia-ai/web-components/styles/*` export map and the `<link>` surface are unchanged); their content moved to single-responsibility files — `foundation/{space,size,radius,motion,elevation}.css`, `type/{scale,roles,elements}.css`, `colors/semantics/{core,buckets,features,data-viz,aliases}.css` — and the global attribute API to `api/{sizing,text,layout}.css`. New `styles/index.css` is the real barrel; the package-root `index.css` re-exports it. **Behavior-neutral** — identical custom-property declaration multiset in the minified bundle (see ADR-0035). Fixed in passing: the dead `--ui-focus` reference in the global `:focus-visible` fallback, and element-typography defaults consolidated into `type/elements.css`.
43
+ - **`scripts/release/check-foundation-layer-placement.mjs`** — new audit (wired into `npm run check`) enforcing the layout: header tags present, primitives free of attribute selectors, the global attribute API confined to `api/`, no orphan files.
44
+ - **`dist/web-components.min.css`** — bundle rebuild reflecting the reorg (no behavioral change).
45
+
46
+ ### Fixed — `<date-range-picker>` popover clipped its second month
47
+
48
+ - **`core/anchor.js`** — the anchored-popover viewport-safety cap was a hard
49
+ `max-width: min(100vw - 1rem, 32rem)`. It's now `min(100vw - 1rem,
50
+ var(--popover-max-width, 32rem))`, so a wide-content popover can raise the
51
+ 32rem cap by setting `--popover-max-width` on the popover element (default
52
+ unchanged → ordinary popovers like `popover-ui` / `menu-ui` / `select-ui` keep
53
+ the 512px cap). Viewport safety still wins.
54
+ - **`components/date-range-picker/date-range-picker.css`** — the preset rail plus
55
+ two side-by-side month panes need ~656px, but the 32rem (512px) cap clipped the
56
+ second month inside the popover. The popover now opts into
57
+ `--popover-max-width: 48rem` (new `--date-range-picker-popover-max-width` token),
58
+ and `[data-calendar-area]` gains `flex-wrap: wrap` so the second pane wraps below
59
+ the first when the viewport clamps the popover narrower than two months (instead
60
+ of clipping). Fixes `<date-range-selector>` too (it embeds the picker). 32/32
61
+ picker tests pass; no regression on other popovers.
62
+
63
+ ### Changed — `<preview-ui>` (docs primitive)
64
+
65
+ - **Side-by-side is the default + self-correcting.** A bare `<preview-ui>` stamps
66
+ `layout="split"` (render | code); a render cell wider than its half-width cell
67
+ downgrades to stacked after layout (rAF + `ResizeObserver`: `split`→`layout="stack"`,
68
+ or a row gains `[data-stack]`), and `overflow-x:auto` lets a page-scale composite
69
+ scroll rather than clip. New `layout="stack"` enum value + CSS.
70
+ - **`dedent` indentation fix** — measures the common indent from the body (lines
71
+ after the first) so markup captured with the opening tag at column 0 no longer
72
+ renders its children deeply over-indented.
73
+ - **`[data-preview-unwrap]`** — multi-element rows show their children's markup, not
74
+ the throwaway layout wrapper, in the code pane.
75
+
3
76
  ## [0.6.47] — 2026-05-29
4
77
 
5
78
  ### Added — `<card-ui>` `[grow]` section attribute
@@ -29,6 +29,20 @@ export class UIBadge extends UIElement {
29
29
  text: string;
30
30
  /** Badge display text. Renderer routes this to the `text` attribute via CSS attr(text) on ::after. */
31
31
  textContent: string;
32
+ /** Fill style — orthogonal to [variant]. Badge defaults to `muted`
33
+ (quiet metadata is the primitive's identity — counts, IDs, status
34
+ pills in dense rows). Three values:
35
+ - `muted` (default) — tinted bg + scheme-paired text. Same as
36
+ the existing family-variant rules.
37
+ - `solid` — saturated bg + on-strong text. Use for hero badges
38
+ where the badge IS the state (e.g. a single inline error). The
39
+ existing `primary` variant is a shortcut for accent + solid.
40
+ - `outline` — transparent bg + family-colored border + family-
41
+ colored text. Lightest visual weight; good in dense data rows.
42
+ Vocabulary mirrors `<tag-ui>` (which defaults to solid, given its
43
+ different role as filter / autocomplete chip).
44
+ */
45
+ tone: 'muted' | 'solid' | 'outline';
32
46
  /** Semantic color variant. */
33
47
  variant: 'default' | 'accent' | 'info' | 'success' | 'warning' | 'danger' | 'primary' | 'muted' | 'neutral';
34
48
  }
@@ -88,10 +88,7 @@
88
88
  "solid",
89
89
  "outline",
90
90
  "ghost",
91
- "primary",
92
- "secondary",
93
- "soft",
94
- "current"
91
+ "primary"
95
92
  ],
96
93
  "default": "solid"
97
94
  }
@@ -33,7 +33,7 @@ export class UIButton extends UIElement {
33
33
  textContent: string;
34
34
  /** Visual style — `solid` (default fill), `outline`, `ghost`. `default` / `primary` are aliases of `solid`. Style is independent of semantic intent — to express destructive / success / info / warning intent, set [color="…"] alongside.
35
35
  For **inline navigation** (Terms of Service, Privacy Policy, footer links, "Sign in" / "Sign up" cross-page affordances) use `<link-ui>` instead — it carries proper `<a href>` semantics, keyboard handling (Enter only, no Space), middle-click open-new-tab, and screen-reader announces "link" instead of "button". Mixing navigation and action affordances under the same primitive is a category error fixed at this junction. */
36
- variant: 'default' | 'solid' | 'outline' | 'ghost' | 'primary' | 'secondary' | 'soft' | 'current';
36
+ variant: 'default' | 'solid' | 'outline' | 'ghost' | 'primary';
37
37
 
38
38
  addEventListener<K extends keyof HTMLElementEventMap>(
39
39
  type: K,
@@ -80,9 +80,6 @@ props:
80
80
  - outline
81
81
  - ghost
82
82
  - primary
83
- - secondary
84
- - soft
85
- - current
86
83
  color:
87
84
  description: >-
88
85
  Semantic intent — composes with [variant]. `<button-ui variant="solid" color="danger">`
@@ -31,6 +31,11 @@
31
31
  "type": "string",
32
32
  "default": ""
33
33
  },
34
+ "month": {
35
+ "description": "Displayed month (YYYY-MM) used when no value is selected — shows a specific month independent of selection. A selected value always takes precedence. Used by date-range-picker to show its end pane one month ahead of the start.",
36
+ "type": "string",
37
+ "default": ""
38
+ },
34
39
  "rangeEnd": {
35
40
  "description": "End of a date range (ISO YYYY-MM-DD). See `rangeStart` for the full contract.",
36
41
  "type": "string",
@@ -61,6 +61,10 @@ export class UICalendarGrid extends UIElement {
61
61
 
62
62
  static properties = {
63
63
  value: { type: String, default: '', reflect: true },
64
+ // Displayed month (`YYYY-MM`) when no `value` is selected — lets a consumer
65
+ // show a specific month independent of selection (e.g. a date-range picker
66
+ // showing its end pane one month ahead of the start pane). Selection wins.
67
+ month: { type: String, default: '', reflect: true },
64
68
  min: { type: String, default: '', reflect: true },
65
69
  max: { type: String, default: '', reflect: true },
66
70
  disabled: { type: Boolean, default: false, reflect: true },
@@ -90,11 +94,14 @@ export class UICalendarGrid extends UIElement {
90
94
  this.setAttribute('role', 'group');
91
95
  if (!this.hasAttribute('aria-label')) this.setAttribute('aria-label', 'Calendar');
92
96
 
93
- // Initialize view to selected date or today.
97
+ // Initialize view to selected date, else the [month] hint, else today.
94
98
  const sel = parseISO(this.value);
95
99
  if (sel) {
96
100
  this.#viewYear = sel.getFullYear();
97
101
  this.#viewMonth = sel.getMonth();
102
+ } else {
103
+ const vm = /^(\d{4})-(\d{2})$/.exec(String(this.month || '').trim());
104
+ if (vm) { this.#viewYear = +vm[1]; this.#viewMonth = +vm[2] - 1; }
98
105
  }
99
106
 
100
107
  if (!this.#bound) {
@@ -15,9 +15,12 @@
15
15
  @scope (calendar-grid-ui) {
16
16
  /* ── Block 1 — TOKENS ── */
17
17
  :where(:scope) {
18
- /* Layout */
18
+ /* Layout
19
+ Width derives from the day-cell size so the grid scales with the
20
+ universal [size] system (sm/md/lg) exactly like select/input/button:
21
+ 7 columns at --a-size + 6 inter-cell gaps' worth of breathing room. */
19
22
  --calendar-grid-gap-default: var(--a-space-1);
20
- --calendar-grid-width-default: 16rem;
23
+ --calendar-grid-width-default: calc(7 * var(--a-size) + 6 * var(--a-space-1));
21
24
 
22
25
  /* Header */
23
26
  --calendar-grid-header-gap-default: var(--a-space-1);
@@ -26,26 +29,32 @@
26
29
  --calendar-grid-title-size-default: var(--a-ui-size);
27
30
  --calendar-grid-title-weight-default: var(--a-weight-medium);
28
31
 
29
- /* Nav buttons (prev/next) */
30
- --calendar-grid-nav-size-default: 1.5rem;
32
+ /* Nav buttons (prev/next) — secondary chrome at one notch below the
33
+ control height (mirrors select's `calc(height - gap)` idiom); icon
34
+ is a directional chevron sized from the universal --a-caret-size. */
35
+ --calendar-grid-nav-size-default: calc(var(--a-size) - var(--a-space-2));
31
36
  --calendar-grid-nav-radius-default: var(--a-radius-sm);
32
37
  --calendar-grid-nav-bg-default: transparent;
33
38
  --calendar-grid-nav-bg-hover-default: var(--a-bg-muted);
34
39
  --calendar-grid-nav-fg-default: var(--a-fg-muted);
35
40
  --calendar-grid-nav-fg-hover-default: var(--a-fg);
36
- --calendar-grid-nav-icon-size-default: 0.75rem;
41
+ --calendar-grid-nav-icon-size-default: var(--a-caret-size);
37
42
 
38
- /* Weekday header */
43
+ /* Weekday header — row height tracks the control height (one notch
44
+ below, like nav); label font scales with the tier via --a-ui-size
45
+ (de-emphasis comes from color + weight, not a frozen small size). */
39
46
  --calendar-grid-weekday-fg-default: var(--a-fg-muted);
40
- --calendar-grid-weekday-size-default: var(--a-ui-sm);
47
+ --calendar-grid-weekday-size-default: var(--a-ui-size);
41
48
  --calendar-grid-weekday-weight-default: var(--a-weight-medium);
42
- --calendar-grid-weekday-height-default: 1.5rem;
49
+ --calendar-grid-weekday-height-default: calc(var(--a-size) - var(--a-space-2));
43
50
  --calendar-grid-weekday-mb-default: var(--a-space-1);
44
51
 
45
- /* Day cells */
46
- --calendar-grid-day-size-default: 2rem;
52
+ /* Day cells — the interactive targets size from --a-size (control
53
+ height) and scale their digits with --a-ui-size, exactly like a
54
+ button/select row. */
55
+ --calendar-grid-day-size-default: var(--a-size);
47
56
  --calendar-grid-day-radius-default: var(--a-radius);
48
- --calendar-grid-day-font-size-default: var(--a-ui-sm);
57
+ --calendar-grid-day-font-size-default: var(--a-ui-size);
49
58
  --calendar-grid-day-bg-default: transparent;
50
59
  --calendar-grid-day-fg-default: var(--a-fg-subtle);
51
60
  --calendar-grid-day-bg-hover-default: var(--a-bg-hover);
@@ -22,6 +22,8 @@ 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
+ /** Displayed month (YYYY-MM) used when no value is selected — shows a specific month independent of selection. A selected value always takes precedence. Used by date-range-picker to show its end pane one month ahead of the start. */
26
+ month: string;
25
27
  /** End of a date range (ISO YYYY-MM-DD). See `rangeStart` for the full contract. */
26
28
  rangeEnd: string;
27
29
  /** 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. */
@@ -22,6 +22,14 @@ props:
22
22
  type: string
23
23
  default: ''
24
24
  reflect: true
25
+ month:
26
+ description: >-
27
+ Displayed month (YYYY-MM) used when no value is selected — shows a specific
28
+ month independent of selection. A selected value always takes precedence.
29
+ Used by date-range-picker to show its end pane one month ahead of the start.
30
+ type: string
31
+ default: ''
32
+ reflect: true
25
33
  min:
26
34
  description: Minimum selectable date in ISO format (YYYY-MM-DD).
27
35
  type: string
@@ -30,7 +30,10 @@
30
30
  --calendar-picker-popover-radius-default: var(--a-radius-lg);
31
31
  --calendar-picker-popover-shadow-default: var(--a-shadow-lg);
32
32
  --calendar-picker-popover-padding-default: var(--a-space-2);
33
- --calendar-picker-popover-width-default: 16rem;
33
+ /* Width derives from the day-grid so the popover scales with [size]:
34
+ 7 columns at --a-size + inter-cell breathing + popover padding both
35
+ sides (border-box). Matches calendar-grid-ui's width formula. */
36
+ --calendar-picker-popover-width-default: calc(7 * var(--a-size) + 6 * var(--a-space-1) + 2 * var(--a-space-2));
34
37
  --calendar-picker-popover-fg-default: var(--a-fg);
35
38
 
36
39
  /* Header */
@@ -40,26 +43,32 @@
40
43
  --calendar-picker-title-size-default: var(--a-ui-size);
41
44
  --calendar-picker-title-weight-default: var(--a-weight-medium);
42
45
 
43
- /* Nav buttons (prev/next) */
44
- --calendar-picker-nav-size-default: 1.5rem;
46
+ /* Nav buttons (prev/next) — secondary chrome at one notch below the
47
+ control height (mirrors select's `calc(height - gap)` idiom); icon
48
+ is a directional chevron sized from the universal --a-caret-size. */
49
+ --calendar-picker-nav-size-default: calc(var(--a-size) - var(--a-space-2));
45
50
  --calendar-picker-nav-radius-default: var(--a-radius-sm);
46
51
  --calendar-picker-nav-bg-default: transparent;
47
52
  --calendar-picker-nav-bg-hover-default: var(--a-bg-muted);
48
53
  --calendar-picker-nav-fg-default: var(--a-fg-muted);
49
54
  --calendar-picker-nav-fg-hover-default: var(--a-fg);
50
- --calendar-picker-nav-icon-size-default: 0.75rem;
55
+ --calendar-picker-nav-icon-size-default: var(--a-caret-size);
51
56
 
52
- /* Weekday header */
57
+ /* Weekday header — row height tracks the control height (one notch
58
+ below, like nav); label font scales with the tier via --a-ui-size
59
+ (de-emphasis comes from color + weight, not a frozen small size). */
53
60
  --calendar-picker-weekday-fg-default: var(--a-fg-muted);
54
- --calendar-picker-weekday-size-default: var(--a-ui-sm);
61
+ --calendar-picker-weekday-size-default: var(--a-ui-size);
55
62
  --calendar-picker-weekday-weight-default: var(--a-weight-medium);
56
- --calendar-picker-weekday-height-default: 1.5rem;
63
+ --calendar-picker-weekday-height-default: calc(var(--a-size) - var(--a-space-2));
57
64
  --calendar-picker-weekday-mb-default: var(--a-space-1);
58
65
 
59
- /* Day cells */
60
- --calendar-picker-day-size-default: 2rem;
66
+ /* Day cells — the interactive targets size from --a-size (control
67
+ height) and scale their digits with --a-ui-size, exactly like a
68
+ button/select row. */
69
+ --calendar-picker-day-size-default: var(--a-size);
61
70
  --calendar-picker-day-radius-default: var(--a-radius);
62
- --calendar-picker-day-font-size-default: var(--a-ui-sm);
71
+ --calendar-picker-day-font-size-default: var(--a-ui-size);
63
72
  --calendar-picker-day-bg-default: transparent;
64
73
  --calendar-picker-day-fg-default: var(--a-fg-subtle);
65
74
  --calendar-picker-day-bg-hover-default: var(--a-bg-hover);
@@ -53,17 +53,14 @@
53
53
  "default": ""
54
54
  },
55
55
  "variant": {
56
- "description": "Visual style. `outline` is an alias for `outlined`; `flat` removes shadow; `soft`/`primary` apply tinted surfaces.",
56
+ "description": "Visual style. `outlined` (alias `outline`) draws a border with no shadow; `filled` uses a tinted canvas surface; `ghost` drops border + shadow.",
57
57
  "type": "string",
58
58
  "enum": [
59
59
  "default",
60
60
  "outlined",
61
61
  "outline",
62
62
  "filled",
63
- "ghost",
64
- "flat",
65
- "soft",
66
- "primary"
63
+ "ghost"
67
64
  ],
68
65
  "default": "default"
69
66
  }
@@ -66,7 +66,9 @@
66
66
 
67
67
  /* ═══════ Variants — token-only overrides ═══════ */
68
68
 
69
- :scope[variant="outlined"] {
69
+ /* `outline` is a documented alias for `outlined` (yaml). */
70
+ :scope[variant="outlined"],
71
+ :scope[variant="outline"] {
70
72
  --card-bg-default: transparent;
71
73
  --card-shadow-default: none;
72
74
  --card-border-default: 1px solid var(--a-border);
@@ -23,6 +23,6 @@ export class UICard extends UIElement {
23
23
  raw: boolean;
24
24
  /** Card scale. Controls inset, radius, gap, and font sizes. Default (empty) = md. */
25
25
  size: 'sm' | 'md' | 'lg';
26
- /** Visual style. `outline` is an alias for `outlined`; `flat` removes shadow; `soft`/`primary` apply tinted surfaces. */
27
- variant: 'default' | 'outlined' | 'outline' | 'filled' | 'ghost' | 'flat' | 'soft' | 'primary';
26
+ /** Visual style. `outlined` (alias `outline`) draws a border with no shadow; `filled` uses a tinted canvas surface; `ghost` drops border + shadow. */
27
+ variant: 'default' | 'outlined' | 'outline' | 'filled' | 'ghost';
28
28
  }
@@ -44,8 +44,8 @@ props:
44
44
  - md
45
45
  - lg
46
46
  variant:
47
- description: Visual style. `outline` is an alias for `outlined`; `flat` removes shadow; `soft`/`primary` apply tinted
48
- surfaces.
47
+ description: Visual style. `outlined` (alias `outline`) draws a border with no
48
+ shadow; `filled` uses a tinted canvas surface; `ghost` drops border + shadow.
49
49
  type: string
50
50
  default: default
51
51
  enum:
@@ -54,9 +54,6 @@ props:
54
54
  - outline
55
55
  - filled
56
56
  - ghost
57
- - flat
58
- - soft
59
- - primary
60
57
  events: {}
61
58
  slots:
62
59
  icon:
@@ -411,6 +411,15 @@ export class UIDateRangePicker extends UIFormElement {
411
411
  }
412
412
  if (!calArea.querySelector(':scope > [data-cal-to]')) {
413
413
  const calTo = this.constructor._pp.calTo.cloneNode(true);
414
+ // Default the end pane to one month after the start pane so a fresh range
415
+ // picker shows two consecutive months (not the same month twice). A `to`
416
+ // value, once selected, overrides this hint inside the grid.
417
+ const fromISO = parseRange(this.value)?.from;
418
+ let y, mo; // mo: 0-based month
419
+ if (fromISO) { const [yy, mm] = fromISO.split('-').map(Number); y = yy; mo = mm - 1; }
420
+ else { const now = new Date(); y = now.getFullYear(); mo = now.getMonth(); }
421
+ mo += 1; if (mo > 11) { mo = 0; y += 1; }
422
+ calTo.setAttribute('month', `${y}-${pad(mo + 1)}`);
414
423
  calArea.appendChild(calTo);
415
424
  }
416
425
  this.#calFromRef = calArea.querySelector(':scope > [data-cal-from]');
@@ -21,6 +21,9 @@
21
21
  --date-range-picker-popover-shadow-default: var(--a-shadow-lg);
22
22
  --date-range-picker-popover-padding-default: var(--a-space-3);
23
23
  --date-range-picker-popover-gap-default: var(--a-space-3);
24
+ /* Wide enough for the preset rail + two side-by-side month panes; raises
25
+ anchor.js's default 32rem cap (which clipped the second month). */
26
+ --date-range-picker-popover-max-width-default: 48rem;
24
27
 
25
28
  /* Preset rail */
26
29
  --date-range-picker-preset-bg-default: transparent;
@@ -132,6 +135,9 @@
132
135
  the popover-ui pattern that uses `:not(:popover-open) { display: none }`. */
133
136
  date-range-picker-ui [slot="popover"] {
134
137
  margin: 0;
138
+ /* Opt into a wider anchor.js max-width cap so both month panes fit side-by-side
139
+ (the 32rem default clipped the second month). Viewport safety still applies. */
140
+ --popover-max-width: var(--date-range-picker-popover-max-width, var(--date-range-picker-popover-max-width-default));
135
141
  padding: var(--date-range-picker-py, var(--date-range-picker-py-default)) var(--date-range-picker-px, var(--date-range-picker-px-default));
136
142
  border: 1px solid var(--date-range-picker-popover-border, var(--date-range-picker-popover-border-default));
137
143
  border-radius: var(--date-range-picker-popover-radius, var(--date-range-picker-popover-radius-default));
@@ -188,10 +194,13 @@ date-range-picker-ui [data-preset-rail] button-ui {
188
194
  justify-content: flex-start;
189
195
  }
190
196
 
191
- /* Calendar area — horizontal layout of two calendar panes. */
197
+ /* Calendar area — horizontal layout of two calendar panes. Wraps the second
198
+ pane below the first when the popover is viewport-clamped narrower than two
199
+ months (instead of clipping it past the popover's right edge). */
192
200
  date-range-picker-ui [data-calendar-area] {
193
201
  grid-column: 2;
194
202
  display: flex;
203
+ flex-wrap: wrap;
195
204
  gap: var(--a-space-3);
196
205
  align-items: flex-start;
197
206
  }
@@ -227,9 +227,14 @@ describe('field-ui', () => {
227
227
  expect(scopeBlock[0]).not.toMatch(/row-gap\s*:/);
228
228
  });
229
229
 
230
- it('CSS source contract: `:scope:has(> [slot="hint"], > [slot="error"])` declares row-gap', () => {
230
+ it('CSS source contract: `:scope:has([slot="hint"], [slot="error"])` declares row-gap', () => {
231
+ // The `>` direct-child combinator is OPTIONAL — field.css uses the
232
+ // descendant form `:has([slot="hint"], [slot="error"])` (v0.6.x); either
233
+ // satisfies the FB-54 row-gap-presence-guard contract.
231
234
  expect(FIELD_CSS).toMatch(
232
- /:scope:has\(>\s*\[slot="hint"\]\s*,\s*>\s*\[slot="error"\]\)\s*\{[^}]*row-gap:\s*var\(--field-gap\)/
235
+ // `var(--field-gap[,)]` accepts both the bare token and the override-aware
236
+ // `var(--field-gap, var(--field-gap-default))` chain (OD-5 token-shadowing).
237
+ /:scope:has\((?:>\s*)?\[slot="hint"\]\s*,\s*(?:>\s*)?\[slot="error"\]\)\s*\{[^}]*row-gap:\s*var\(--field-gap[,)]/
233
238
  );
234
239
  });
235
240
  });
@@ -39,6 +39,8 @@
39
39
  "accent",
40
40
  "success",
41
41
  "warning",
42
+ "danger",
43
+ "info",
42
44
  "data-ramp"
43
45
  ],
44
46
  "default": "data-ramp"
@@ -24,7 +24,7 @@ export class UIHeatmap extends UIElement {
24
24
  /** Aspect ratio */
25
25
  aspect: 'square' | 'wide';
26
26
  /** Color ramp */
27
- colorScheme: 'accent' | 'success' | 'warning' | 'data-ramp';
27
+ colorScheme: 'accent' | 'success' | 'warning' | 'danger' | 'info' | 'data-ramp';
28
28
  /** Column count */
29
29
  cols: number;
30
30
  /** Hide the Less/More legend strip */
@@ -33,6 +33,8 @@ props:
33
33
  - accent
34
34
  - success
35
35
  - warning
36
+ - danger
37
+ - info
36
38
  - data-ramp
37
39
  attribute: color-scheme
38
40
  cols:
@@ -87,6 +87,7 @@ export { UITableOfContents } from './toc/toc.js';
87
87
  export { UIQRCode } from './qr-code/qr-code.js';
88
88
  export { UIPagination } from './pagination/pagination.js';
89
89
  export { UICode } from './code/code.js';
90
+ export { UIPreview } from './preview/preview.js';
90
91
  export { UIList, UIListItem } from './list/list.js';
91
92
  export { UIListWindow } from './list-window/list-window.js';
92
93
  export { UIMenu, UIMenuItem, UIMenuDivider } from './menu/menu.js';
@@ -0,0 +1,93 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://adiaui.dev/a2ui/v0_9/components/Preview.json",
4
+ "title": "Preview",
5
+ "description": "Live code + render in one frame, from a single source. Wrap any authored AdiaUI markup: the same HTML renders LIVE in a stage and appears beside (or below) it as escaped, syntax-highlighted, copyable source via a nested <code-ui>. The code can never drift from the render — it IS the render's source. Batteries-included + HTML-first by construction: write one block of HTML, no inline styles, no JS wiring, and both panes appear. Use it for every component/recipe example so the primary snippet is always real, copyable HTML shown next to the working component.",
6
+ "type": "object",
7
+ "allOf": [
8
+ {
9
+ "$ref": "common_types.json#/$defs/ComponentCommon"
10
+ },
11
+ {
12
+ "$ref": "common_types.json#/$defs/CatalogComponentCommon"
13
+ }
14
+ ],
15
+ "properties": {
16
+ "codeFirst": {
17
+ "description": "Show the code pane before (above / left of) the render pane. Default is render-first.",
18
+ "type": "boolean",
19
+ "default": false
20
+ },
21
+ "component": {
22
+ "const": "Preview"
23
+ },
24
+ "language": {
25
+ "description": "Language hint forwarded to the nested <code-ui> for syntax highlighting. Demos are HTML, so this defaults to `html`.",
26
+ "type": "string",
27
+ "default": "html"
28
+ },
29
+ "layout": {
30
+ "description": "Pane arrangement. Defaults to `split` — render and code side-by-side in a responsive 2-column grid that collapses to stacked on narrow widths (a bare `<preview-ui>` stamps `layout=\"split\"` on connect). Use `stack` to force the render stacked above the code; the docs auto-apply `stack` to wide self-framing demos (card / shell / table) that read cramped at half width. The `rows` attribute is a separate gallery mode and overrides this.",
31
+ "type": "string",
32
+ "enum": [
33
+ "split",
34
+ "stack"
35
+ ],
36
+ "default": ""
37
+ },
38
+ "rows": {
39
+ "description": "Gallery mode — treat each direct child as a SEPARATE example and lay each out as its own `[render | code]` row (live sample left, its own source right), stacked with dividers. Without `rows`, the whole slotted markup is one render + one code block. An optional `data-preview-label` on a child surfaces a caption above that row's sample.",
40
+ "type": "boolean",
41
+ "default": false
42
+ }
43
+ },
44
+ "required": [
45
+ "component"
46
+ ],
47
+ "unevaluatedProperties": false,
48
+ "x-adiaui": {
49
+ "anti_patterns": [],
50
+ "category": "display",
51
+ "composes": [],
52
+ "events": {},
53
+ "examples": [],
54
+ "keywords": [
55
+ "preview",
56
+ "example",
57
+ "demo",
58
+ "code-preview",
59
+ "live-preview",
60
+ "playground",
61
+ "codepen"
62
+ ],
63
+ "name": "UIPreview",
64
+ "related": [
65
+ "Code",
66
+ "Card"
67
+ ],
68
+ "slots": {
69
+ "default": {
70
+ "description": "The authored markup to preview. Captured verbatim on connect: re-parsed into the live render stage AND shown literally in the code pane. Any valid AdiaUI HTML — one element or many siblings."
71
+ }
72
+ },
73
+ "states": [
74
+ {
75
+ "description": "Default, the only state.",
76
+ "name": "idle"
77
+ }
78
+ ],
79
+ "status": "stable",
80
+ "synonyms": {
81
+ "preview": [
82
+ "example",
83
+ "demo",
84
+ "sandbox",
85
+ "live-preview"
86
+ ]
87
+ },
88
+ "tag": "preview-ui",
89
+ "tokens": {},
90
+ "traits": [],
91
+ "version": 1
92
+ }
93
+ }