@skra/ui 0.6.0 → 0.7.0

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.
@@ -1,6 +1,6 @@
1
1
  # Consuming Skra — Agent Guide (Core)
2
2
 
3
- > **DRAFT (2026-06-25; 8th section added 2026-08-30).** All 8 sections drafted. Snippets are grounded in source (verified
3
+ > **DRAFT (2026-06-25; 8th section added 2026-08-30; 9th — Feedback — 2026-09-27).** All 9 sections drafted. Snippets are grounded in source (verified
4
4
  > against `libs/ui/*`) + the `apps/dogfood` friction journal (`F-n`) + the Iron Boundaries.
5
5
  > Still draft: not yet referenced from a real consumer repo, not lint-gated against ADR drift,
6
6
  > and cross-engine/Safari caveats inherit Skra's own open item O-9.
@@ -57,6 +57,7 @@ Violating these is a review blocker in a consumer repo just as inside Skra.
57
57
  | **Forms & value binding** | `forms-and-binding.md` | Wiring an input / select / checkbox / rating to Signal Forms, Reactive Forms, or `ngModel` | ✅ draft |
58
58
  | **Accessible names** | `accessible-names.md` | Naming buttons, icon-only controls, overlays; using `skra-sr-only` | ✅ draft |
59
59
  | **Theming & encapsulation** | `theming-and-encapsulation.md` | Skins, dark mode, density; mounting under Shadow DOM / a microfrontend / an iframe | ✅ draft |
60
+ | **Feedback** | `feedback.md` | Alert vs toast vs badge vs field error; `live` announcing; dismissal; an alert with a next-step action | ✅ draft |
60
61
  | **Overlays** | `overlays.md` | Dialog / tooltip / popover / menu / select in the top layer; shadow & iframe limits | ✅ draft |
61
62
  | **Layout** | `layout.md` | Spacing & composition with Stack / Box / Surface / Grid; building a card; the gap scale | ✅ draft |
62
63
  | **Wrapping Skra** | `wrapping-patterns.md` | Building your own higher-level components over Skra atoms (simplified API) | ✅ draft |
@@ -74,6 +75,7 @@ Violating these is a review blocker in a consumer repo just as inside Skra.
74
75
  | Name an icon-only button | `accessible-names.md` |
75
76
  | Switch skin / dark mode at runtime | `theming-and-encapsulation.md` |
76
77
  | Mount Skra inside a Web Component / microfrontend | `theming-and-encapsulation.md` |
78
+ | Show an alert / toast / badge, or add a "Try again" button to an alert | `feedback.md` |
77
79
  | Open a dialog or tooltip | `overlays.md` |
78
80
  | Space components apart | `layout.md` |
79
81
  | Build a card / panel / tile (there is no `skra-card`) | `layout.md` (Surface) |
@@ -42,7 +42,8 @@ must be loaded (and bridged into any shadow root — see `theming-and-encapsulat
42
42
  or the text renders visibly.
43
43
 
44
44
  > The same pattern names other built-in sr-only slots, e.g. `[skra-alert-close-label]` on
45
- > `skra-alert`'s dismiss button.
45
+ > `skra-alert`'s dismiss button. An alert **action** (`[skra-alert-actions]`) names itself by its
46
+ > visible text (Path 1); in a live alert that label is announced with the message (`feedback.md`).
46
47
 
47
48
  ## Path 3 — `aria-label` on an icon-only host
48
49
 
@@ -0,0 +1,100 @@
1
+ # Feedback — Alerts, Toasts, Badges
2
+
3
+ > Load this for: telling the user what happened — an in-page alert, a transient toast, a status
4
+ > badge — and putting a next step ("Try again") inside an alert.
5
+ > Governed by ADR 0052 (live-region semantics), ADR 035 (intent / emphasis) and ADR 0059
6
+ > (actions on an intent-tinted ground).
7
+
8
+ ## Which one?
9
+
10
+ | You need to… | Use |
11
+ | ---------------------------------------------------------- | ---------------------------------------------------------------------- |
12
+ | Say something about a page or a section, and keep it there | `<skra-alert>` (`@skra/ui/alert`) |
13
+ | Confirm an action briefly without moving focus ("Saved") | `<skra-toast>` inside one `<skra-toast-region>` (`@skra/ui/toast`) |
14
+ | Label a thing with a short status ("Draft", "3 new") | `<skra-badge>` (`@skra/ui/badge`) |
15
+ | Say what is wrong with ONE form value | `<skra-error>` inside `<skra-field>` (`@skra/ui/field`) — not an alert |
16
+
17
+ The alert, the toast and the badge take the same two look-free axes (`<skra-error>` is always an error): `intent` (`neutral` · `info` · `success` · `warning` ·
18
+ `danger`) and `emphasis` (`high` = filled, `medium` = soft; the default). Put the severity in the
19
+ **text** too — colour and icon alone do not carry meaning (WCAG 1.4.1).
20
+
21
+ ## Announcing (`live`)
22
+
23
+ `live` decides whether a screen reader announces the content when it appears; it maps to the
24
+ implicit `role` (`polite` → `status`, `assertive` → `alert`). It is about **how the content
25
+ arrives**, not how severe it is:
26
+
27
+ - present when the page loads → leave `live="off"` (alert default);
28
+ - inserted after the user did something → `live="polite"`, or `"assertive"` for a failure that
29
+ blocks them.
30
+
31
+ Skra sets the role only — never add `aria-live` / `aria-atomic` yourself. A live region announces
32
+ its whole text, **including the labels of the controls inside it** (the dismiss label, an action).
33
+
34
+ ## Dismissal is yours
35
+
36
+ `dismissible` renders a close control and emits `(dismissed)`. The alert does **not** remove
37
+ itself — you do, with `@if`, the same way you showed it. Name the control with a projected
38
+ `[skra-alert-close-label]` (visually hidden text; `accessible-names.md`). If the close control had
39
+ focus, move focus somewhere sensible before you remove the alert.
40
+
41
+ ```html
42
+ @if (saveFailed()) {
43
+ <skra-alert intent="danger" live="assertive" dismissible (dismissed)="saveFailed.set(false)">
44
+ Could not save.
45
+ <span skra-alert-close-label class="skra-sr-only">Dismiss</span>
46
+ </skra-alert>
47
+ }
48
+ ```
49
+
50
+ ## An alert with an action
51
+
52
+ Mark each next-step button `[skra-alert-actions]`. The alert places the actions **below the
53
+ message**, as a row that wraps on a narrow container, and never lets them collide with the close
54
+ control. Several actions are fine; they keep your order.
55
+
56
+ ```html
57
+ <skra-alert intent="danger" live="assertive">
58
+ <span skra-alert-title>Could not save</span>
59
+ Your changes are kept on this device. Check your connection and try again.
60
+ <button skraButton skra-alert-actions emphasis="medium" type="button" (click)="retry()">Try again</button>
61
+ </skra-alert>
62
+ ```
63
+
64
+ **The action keeps its own meaning.** The alert does not pass its `intent` to the button. A retry
65
+ inside a `danger` alert is not a destructive action, so it must not be a `danger` button — that
66
+ colour means "this deletes something". Choose the button's `intent` for what the button **does**,
67
+ exactly as anywhere else.
68
+
69
+ **What is guaranteed legible on the alert's colour.** Skra measures these combinations in every
70
+ state (rest, hover, pressed, focus), both colour schemes and every shipped skin:
71
+
72
+ | Alert | Guaranteed actions |
73
+ | ----------------------------- | ------------------------------------------------------------------------------- |
74
+ | `emphasis="medium"` (default) | a `neutral` button at any emphasis; a button of any intent at `emphasis="high"` |
75
+ | `emphasis="high"` (filled) | a button of any intent at `emphasis="high"` **other than the alert's own** |
76
+
77
+ - The zero-config `<button skraButton skra-alert-actions>` (`neutral`, `high`) is guaranteed on
78
+ every alert except a `neutral` + `high` one.
79
+ - **Not supported:** a coloured `medium`/`low` button; a `medium`/`low` button on a filled alert
80
+ (it measured as low as 1.2:1); a `high` button in the alert's own intent (it has the alert's
81
+ exact colour — no visible button). Nothing stops you writing them; nothing guarantees them either.
82
+ - Only `button[skraButton]` is measured in the actions row. A link or a badge there is on you.
83
+ - The focus ring of the actions follows the alert (on a filled alert it switches to the alert's
84
+ text colour, because the page ring disappears on the fill). To re-colour it, target the alert's
85
+ per-variant hook `--skra-comp-alert-focus-ring-color-<intent>-<emphasis>` in a skin overlay preset
86
+ (the only tier its manifest allows) — never the button's ring.
87
+ - An action that **navigates** is still a `<button>` that routes — Skra has no link styled as a
88
+ button (ADR 032).
89
+
90
+ ## Toasts
91
+
92
+ One `<skra-toast-region>` near the app root announces every toast from persistent live regions;
93
+ each `<skra-toast>` sets `intent`, `emphasis`, `live` (default `polite`), `duration` (ms; pauses on
94
+ hover / focus) and `dismissible` → `(dismissed)`. Removal is yours, as for the alert. Toasts do
95
+ not take actions yet.
96
+
97
+ ## Badges
98
+
99
+ `<skra-badge>` is a small, inline, non-interactive status label (`intent`, `emphasis`, optional
100
+ `[skra-badge-icon]`). Leave `live="off"` unless the badge changes while the user watches it.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, input, booleanAttribute, output, contentChild, computed, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
2
+ import { Directive, input, booleanAttribute, output, contentChild, computed, contentChildren, ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/core';
3
3
 
4
4
  /**
5
5
  * Marker directive for the leading icon slot of `<skra-alert>`.
@@ -37,6 +37,44 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
37
37
  standalone: true,
38
38
  }]
39
39
  }] });
40
+ /**
41
+ * Marker directive for an ACTION of `<skra-alert>` — "what to do next" ("Try again").
42
+ * Put it on each action; several are allowed and keep the consumer's order. Detected via
43
+ * `contentChildren` (ADR 020) to render the actions region below the message only when one
44
+ * exists. The region sits inside the content column, so it never collides with the dismiss
45
+ * control.
46
+ *
47
+ * The action keeps its OWN meaning: the alert never sets or changes a projected button's
48
+ * `intent` / `emphasis` (ADR 0059 R59.1) — a retry inside a danger alert is not a destructive
49
+ * action. What the alert owns is the region's layout and the focus ring its actions draw on the
50
+ * alert's fill (R59.3). Guaranteed legible on the alert's fill (ADR 0059 R59.2 — the gate
51
+ * measures exactly these):
52
+ *
53
+ * | Alert emphasis | Guaranteed actions |
54
+ * | ------------------- | --------------------------------------------------------------- |
55
+ * | `medium` (default) | `neutral` at any emphasis; any intent at `emphasis="high"` |
56
+ * | `high` | any intent at `emphasis="high"` other than the alert's intent |
57
+ *
58
+ * Anything else (a coloured `medium`/`low` action, a `medium`/`low` action on a `high` alert,
59
+ * a `high` action in the alert's own intent) is unsupported. The zero-config
60
+ * `<button skraButton skra-alert-actions>` (`neutral × high`) is guaranteed everywhere except
61
+ * on a `neutral × high` alert. Admitted atom: `button[skraButton]`.
62
+ *
63
+ * Announcement: a live alert (`live="polite"|"assertive"`) announces its whole text, action
64
+ * labels included (the implicit `role` carries `aria-atomic`, ADR 0052) — the label tells the
65
+ * user an action exists.
66
+ */
67
+ class SkraAlertActions {
68
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraAlertActions, deps: [], target: i0.ɵɵFactoryTarget.Directive });
69
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: SkraAlertActions, isStandalone: true, selector: "[skra-alert-actions]", ngImport: i0 });
70
+ }
71
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraAlertActions, decorators: [{
72
+ type: Directive,
73
+ args: [{
74
+ selector: '[skra-alert-actions]',
75
+ standalone: true,
76
+ }]
77
+ }] });
40
78
 
41
79
  /**
42
80
  * `<skra-alert>` — in-content, page/section-level feedback message (Feedback/Status
@@ -53,6 +91,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
53
91
  * Forge does NOT remove itself from the DOM — the consumer owns removal via `@if`
54
92
  * (agnostic-atom doctrine). The close control's accessible name comes from a projected
55
93
  * `[skra-alert-close-label]` (sr-only; ADR 033 Path 2) — the "×" glyph is `aria-hidden`.
94
+ *
95
+ * Actions (GitHub #4, ADR 0059): mark each next-step button `[skra-alert-actions]`; they render
96
+ * in a region below the message. The alert owns that region's layout and its focus ring, never
97
+ * the actions' meaning — see `SkraAlertActions` for the guaranteed combinations.
56
98
  */
57
99
  class SkraAlert {
58
100
  // --- Variant Surface (ADR 035) ---
@@ -75,6 +117,12 @@ class SkraAlert {
75
117
  ...(ngDevMode ? [{ debugName: "titleSlot" }] : /* istanbul ignore next */ []));
76
118
  hasTitle = computed(() => !!this.titleSlot(), /* @ts-ignore */
77
119
  ...(ngDevMode ? [{ debugName: "hasTitle" }] : /* istanbul ignore next */ []));
120
+ // Several actions are allowed (consumer order) — hence contentChildren, not contentChild.
121
+ // The alert never touches their intent/emphasis (ADR 0059 R59.1); see SkraAlertActions.
122
+ actionSlots = contentChildren(SkraAlertActions, /* @ts-ignore */
123
+ ...(ngDevMode ? [{ debugName: "actionSlots" }] : /* istanbul ignore next */ []));
124
+ hasActions = computed(() => this.actionSlots().length > 0, /* @ts-ignore */
125
+ ...(ngDevMode ? [{ debugName: "hasActions" }] : /* istanbul ignore next */ []));
78
126
  /**
79
127
  * Map `live` politeness to the implicit-live ARIA role (ADR 0052). The role
80
128
  * carries `aria-live` + `aria-atomic` implicitly; `off` → no live region.
@@ -94,11 +142,11 @@ class SkraAlert {
94
142
  this.dismissed.emit();
95
143
  }
96
144
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraAlert, deps: [], target: i0.ɵɵFactoryTarget.Component });
97
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraAlert, isStandalone: true, selector: "skra-alert", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, emphasis: { classPropertyName: "emphasis", publicName: "emphasis", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-emphasis": "emphasis()", "attr.role": "liveRole()", "attr.data-skra-has-icon": "hasIcon() ? \"\" : null", "attr.data-skra-has-title": "hasTitle() ? \"\" : null" } }, queries: [{ propertyName: "iconSlot", first: true, predicate: SkraAlertIcon, descendants: true, isSignal: true }, { propertyName: "titleSlot", first: true, predicate: SkraAlertTitle, descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasIcon()) {\r\n<span class=\"skra-alert-icon\">\r\n <ng-content select=\"[skra-alert-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-alert-content\">\r\n @if (hasTitle()) {\r\n <div class=\"skra-alert-title\">\r\n <ng-content select=\"[skra-alert-title]\"></ng-content>\r\n </div>\r\n }\r\n <div class=\"skra-alert-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-alert-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-alert-dismiss-glyph\" aria-hidden=\"true\">&times;</span>\r\n <ng-content select=\"[skra-alert-close-label]\"></ng-content>\r\n</button>\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-alert-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-alert-background);color:var(--skra-comp-alert-foreground);border-color:var(--skra-comp-alert-border-color);border-width:var(--skra-comp-alert-border-width);border-style:var(--skra-comp-alert-border-style);border-radius:var(--skra-comp-alert-radius);padding-block:var(--skra-comp-alert-padding-block);padding-inline:var(--skra-comp-alert-padding-inline);box-shadow:var(--skra-comp-alert-shadow)}:host([data-skra-emphasis=high]){--skra-comp-alert-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-alert-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-alert-icon-size)}.skra-alert-content{flex:1 1 auto;min-inline-size:0;display:flex;flex-direction:column;gap:var(--skra-comp-alert-title-gap)}.skra-alert-title{font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing)}.skra-alert-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-alert-dismiss-size);block-size:var(--skra-comp-alert-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-alert-radius);transition:opacity var(--skra-comp-alert-motion-duration) var(--skra-comp-alert-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-alert-dismiss:hover{opacity:.7}}.skra-alert-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-alert-focus-ring-color);outline-width:var(--skra-comp-alert-focus-ring-width);outline-offset:2px}.skra-alert-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){.skra-alert-dismiss{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
145
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraAlert, isStandalone: true, selector: "skra-alert", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, emphasis: { classPropertyName: "emphasis", publicName: "emphasis", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-emphasis": "emphasis()", "attr.role": "liveRole()", "attr.data-skra-has-icon": "hasIcon() ? \"\" : null", "attr.data-skra-has-title": "hasTitle() ? \"\" : null", "attr.data-skra-has-actions": "hasActions() ? \"\" : null" } }, queries: [{ propertyName: "iconSlot", first: true, predicate: SkraAlertIcon, descendants: true, isSignal: true }, { propertyName: "titleSlot", first: true, predicate: SkraAlertTitle, descendants: true, isSignal: true }, { propertyName: "actionSlots", predicate: SkraAlertActions, isSignal: true }], ngImport: i0, template: "@if (hasIcon()) {\n<span class=\"skra-alert-icon\">\n <ng-content select=\"[skra-alert-icon]\"></ng-content>\n</span>\n}\n\n<div class=\"skra-alert-content\">\n @if (hasTitle()) {\n <div class=\"skra-alert-title\">\n <ng-content select=\"[skra-alert-title]\"></ng-content>\n </div>\n }\n <div class=\"skra-alert-body\">\n <ng-content></ng-content>\n </div>\n @if (hasActions()) {\n <div class=\"skra-alert-actions\">\n <ng-content select=\"[skra-alert-actions]\"></ng-content>\n </div>\n }\n</div>\n\n@if (dismissible()) {\n<button type=\"button\" class=\"skra-alert-dismiss\" (click)=\"onDismiss()\">\n <span class=\"skra-alert-dismiss-glyph\" aria-hidden=\"true\">&times;</span>\n <ng-content select=\"[skra-alert-close-label]\"></ng-content>\n</button>\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-alert-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-alert-background);color:var(--skra-comp-alert-foreground);border-color:var(--skra-comp-alert-border-color);border-width:var(--skra-comp-alert-border-width);border-style:var(--skra-comp-alert-border-style);border-radius:var(--skra-comp-alert-radius);padding-block:var(--skra-comp-alert-padding-block);padding-inline:var(--skra-comp-alert-padding-inline);box-shadow:var(--skra-comp-alert-shadow)}:host([data-skra-emphasis=high]){--skra-comp-alert-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-neutral-high, var(--skra-sys-color-neutral-contrast) )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-medium, var(--skra-sys-color-neutral-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-neutral-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-info-high, var(--skra-sys-color-info-contrast) )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-medium, var(--skra-sys-color-info-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-info-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-success-high, var(--skra-sys-color-success-contrast) )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-medium, var(--skra-sys-color-success-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-success-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-warning-high, var(--skra-sys-color-warning-contrast) )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-medium, var(--skra-sys-color-warning-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-warning-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-danger-high, var(--skra-sys-color-danger-contrast) )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-medium, var(--skra-sys-color-danger-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-danger-medium, var(--skra-sys-color-focus-ring) )}.skra-alert-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-alert-icon-size)}.skra-alert-content{flex:1 1 auto;min-inline-size:0;display:flex;flex-direction:column;gap:var(--skra-comp-alert-title-gap)}.skra-alert-title{font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing)}.skra-alert-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--skra-comp-alert-actions-gap);padding-block-start:var(--skra-comp-alert-actions-gap);--skra-comp-button-focus-ring-color: var(--skra-comp-alert-focus-ring-color)}.skra-alert-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-alert-dismiss-size);block-size:var(--skra-comp-alert-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-alert-radius);transition:opacity var(--skra-comp-alert-motion-duration) var(--skra-comp-alert-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-alert-dismiss:hover{opacity:.7}}.skra-alert-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-alert-focus-ring-color);outline-width:var(--skra-comp-alert-focus-ring-width);outline-offset:2px}.skra-alert-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){.skra-alert-dismiss{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
98
146
  }
99
147
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraAlert, decorators: [{
100
148
  type: Component,
101
- args: [{ selector: 'skra-alert', standalone: true, imports: [SkraAlertIcon, SkraAlertTitle], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
149
+ args: [{ selector: 'skra-alert', standalone: true, imports: [SkraAlertIcon, SkraAlertTitle, SkraAlertActions], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
102
150
  // Variant Surface reflection (ADR 035 §3.5)
103
151
  '[attr.data-skra-intent]': 'intent()',
104
152
  '[attr.data-skra-emphasis]': 'emphasis()',
@@ -107,12 +155,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
107
155
  // Smart Slots layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)
108
156
  '[attr.data-skra-has-icon]': 'hasIcon() ? "" : null',
109
157
  '[attr.data-skra-has-title]': 'hasTitle() ? "" : null',
110
- }, template: "@if (hasIcon()) {\r\n<span class=\"skra-alert-icon\">\r\n <ng-content select=\"[skra-alert-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-alert-content\">\r\n @if (hasTitle()) {\r\n <div class=\"skra-alert-title\">\r\n <ng-content select=\"[skra-alert-title]\"></ng-content>\r\n </div>\r\n }\r\n <div class=\"skra-alert-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-alert-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-alert-dismiss-glyph\" aria-hidden=\"true\">&times;</span>\r\n <ng-content select=\"[skra-alert-close-label]\"></ng-content>\r\n</button>\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-alert-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-alert-background);color:var(--skra-comp-alert-foreground);border-color:var(--skra-comp-alert-border-color);border-width:var(--skra-comp-alert-border-width);border-style:var(--skra-comp-alert-border-style);border-radius:var(--skra-comp-alert-radius);padding-block:var(--skra-comp-alert-padding-block);padding-inline:var(--skra-comp-alert-padding-inline);box-shadow:var(--skra-comp-alert-shadow)}:host([data-skra-emphasis=high]){--skra-comp-alert-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-alert-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-alert-icon-size)}.skra-alert-content{flex:1 1 auto;min-inline-size:0;display:flex;flex-direction:column;gap:var(--skra-comp-alert-title-gap)}.skra-alert-title{font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing)}.skra-alert-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-alert-dismiss-size);block-size:var(--skra-comp-alert-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-alert-radius);transition:opacity var(--skra-comp-alert-motion-duration) var(--skra-comp-alert-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-alert-dismiss:hover{opacity:.7}}.skra-alert-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-alert-focus-ring-color);outline-width:var(--skra-comp-alert-focus-ring-width);outline-offset:2px}.skra-alert-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){.skra-alert-dismiss{transition:none}}\n"] }]
111
- }], propDecorators: { intent: [{ type: i0.Input, args: [{ isSignal: true, alias: "intent", required: false }] }], emphasis: [{ type: i0.Input, args: [{ isSignal: true, alias: "emphasis", required: false }] }], live: [{ type: i0.Input, args: [{ isSignal: true, alias: "live", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }], iconSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SkraAlertIcon), { isSignal: true }] }], titleSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SkraAlertTitle), { isSignal: true }] }] } });
158
+ '[attr.data-skra-has-actions]': 'hasActions() ? "" : null',
159
+ }, template: "@if (hasIcon()) {\n<span class=\"skra-alert-icon\">\n <ng-content select=\"[skra-alert-icon]\"></ng-content>\n</span>\n}\n\n<div class=\"skra-alert-content\">\n @if (hasTitle()) {\n <div class=\"skra-alert-title\">\n <ng-content select=\"[skra-alert-title]\"></ng-content>\n </div>\n }\n <div class=\"skra-alert-body\">\n <ng-content></ng-content>\n </div>\n @if (hasActions()) {\n <div class=\"skra-alert-actions\">\n <ng-content select=\"[skra-alert-actions]\"></ng-content>\n </div>\n }\n</div>\n\n@if (dismissible()) {\n<button type=\"button\" class=\"skra-alert-dismiss\" (click)=\"onDismiss()\">\n <span class=\"skra-alert-dismiss-glyph\" aria-hidden=\"true\">&times;</span>\n <ng-content select=\"[skra-alert-close-label]\"></ng-content>\n</button>\n}\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-alert-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-alert-background);color:var(--skra-comp-alert-foreground);border-color:var(--skra-comp-alert-border-color);border-width:var(--skra-comp-alert-border-width);border-style:var(--skra-comp-alert-border-style);border-radius:var(--skra-comp-alert-radius);padding-block:var(--skra-comp-alert-padding-block);padding-inline:var(--skra-comp-alert-padding-inline);box-shadow:var(--skra-comp-alert-shadow)}:host([data-skra-emphasis=high]){--skra-comp-alert-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-neutral-high, var(--skra-sys-color-neutral-contrast) )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-neutral-medium, var(--skra-sys-color-neutral-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-neutral-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-info-high, var(--skra-sys-color-info-contrast) )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-info-medium, var(--skra-sys-color-info-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-info-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-success-high, var(--skra-sys-color-success-contrast) )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-success-medium, var(--skra-sys-color-success-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-success-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-warning-high, var(--skra-sys-color-warning-contrast) )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-warning-medium, var(--skra-sys-color-warning-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-warning-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-high, transparent );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-danger-high, var(--skra-sys-color-danger-contrast) )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-alert-background: var( --skra-comp-alert-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-alert-foreground: var( --skra-comp-alert-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-alert-border-color: var( --skra-comp-alert-border-color-danger-medium, var(--skra-sys-color-danger-border) );--skra-comp-alert-focus-ring-color: var( --skra-comp-alert-focus-ring-color-danger-medium, var(--skra-sys-color-focus-ring) )}.skra-alert-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-alert-icon-size)}.skra-alert-content{flex:1 1 auto;min-inline-size:0;display:flex;flex-direction:column;gap:var(--skra-comp-alert-title-gap)}.skra-alert-title{font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing)}.skra-alert-actions{display:flex;flex-wrap:wrap;align-items:center;gap:var(--skra-comp-alert-actions-gap);padding-block-start:var(--skra-comp-alert-actions-gap);--skra-comp-button-focus-ring-color: var(--skra-comp-alert-focus-ring-color)}.skra-alert-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-alert-dismiss-size);block-size:var(--skra-comp-alert-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-alert-radius);transition:opacity var(--skra-comp-alert-motion-duration) var(--skra-comp-alert-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-alert-dismiss:hover{opacity:.7}}.skra-alert-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-alert-focus-ring-color);outline-width:var(--skra-comp-alert-focus-ring-width);outline-offset:2px}.skra-alert-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){.skra-alert-dismiss{transition:none}}\n"] }]
160
+ }], propDecorators: { intent: [{ type: i0.Input, args: [{ isSignal: true, alias: "intent", required: false }] }], emphasis: [{ type: i0.Input, args: [{ isSignal: true, alias: "emphasis", required: false }] }], live: [{ type: i0.Input, args: [{ isSignal: true, alias: "live", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }], iconSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SkraAlertIcon), { isSignal: true }] }], titleSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SkraAlertTitle), { isSignal: true }] }], actionSlots: [{ type: i0.ContentChildren, args: [i0.forwardRef(() => SkraAlertActions), { isSignal: true }] }] } });
112
161
 
113
162
  /**
114
163
  * Generated bundle index. Do not edit.
115
164
  */
116
165
 
117
- export { SkraAlert, SkraAlertIcon, SkraAlertTitle };
166
+ export { SkraAlert, SkraAlertActions, SkraAlertIcon, SkraAlertTitle };
118
167
  //# sourceMappingURL=skra-ui-alert.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-alert.mjs","sources":["../../../../libs/ui/alert/src/lib/alert.directives.ts","../../../../libs/ui/alert/src/lib/alert/alert.ts","../../../../libs/ui/alert/src/lib/alert/alert.html","../../../../libs/ui/alert/src/skra-ui-alert.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n/**\n * Marker directive for the leading icon slot of `<skra-alert>`.\n * Detected via `contentChild` (ADR 020 Smart Slots v2.0) to toggle the icon\n * wrapper without emitting an empty DOM node. Feedback-local (not the button\n * lib's `[skra-start]`) to avoid a cross-lib marker dependency.\n */\n@Directive({\n selector: '[skra-alert-icon]',\n standalone: true,\n})\nexport class SkraAlertIcon {}\n\n/**\n * Marker directive for the OPTIONAL title slot of `<skra-alert>` — a short, bold\n * heading rendered above the message. Detected via `contentChild` (ADR 020) to\n * toggle the title row. It is styled bold via a typography role but is NOT a\n * semantic heading (`<h*>`): an alert title is not part of the document outline,\n * and a heading would pollute screen-reader heading navigation (especially for a\n * dynamically-injected alert). The live region announces title + body atomically.\n */\n@Directive({\n selector: '[skra-alert-title]',\n standalone: true,\n})\nexport class SkraAlertTitle {}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n booleanAttribute,\n computed,\n contentChild,\n input,\n output,\n} from '@angular/core';\nimport { SkraAlertIcon, SkraAlertTitle } from '../alert.directives';\n\n/**\n * AlertIntent — semantic feedback meaning (ADR 035 §3.1, downward subset).\n * Excludes the action intents `primary`/`secondary` (meaningless for a status\n * message). Closed enum; extension requires an ADR 035 amendment.\n */\nexport type AlertIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\n/**\n * AlertEmphasis — visual loudness within the chosen intent (ADR 035 §3.1, subset).\n * `high` = filled banner, `medium` = soft/tinted. `low` deferred.\n */\nexport type AlertEmphasis = 'high' | 'medium';\n\n/**\n * AlertLive — screen-reader announcement politeness (ADR 0052). Maps to the\n * implicit-live ARIA role; politeness is a property of USE (static vs injected),\n * NOT of intent.\n */\nexport type AlertLive = 'off' | 'polite' | 'assertive';\n\n/**\n * `<skra-alert>` — in-content, page/section-level feedback message (Feedback/Status\n * family, ADR 0052). Serves BOTH a static notification (`live=\"off\"`, present at load)\n * and a dynamically-injected alert (`live=\"polite\"|\"assertive\"`, announced on insertion).\n *\n * SRP-distinct from `<skra-error>` (form-validation-bound, `SkraFieldContext`, error-only).\n *\n * Announcement (ADR 0052): the `live` input maps to the implicit-live ARIA role\n * (`status`/`alert`) — which carries `aria-live` + `aria-atomic` implicitly. NO explicit\n * `aria-live` is set (that would be redundant/contradictory; the `skra-error` pattern).\n *\n * Dismissal: `dismissible` renders a built-in close control that emits `(dismissed)`.\n * Forge does NOT remove itself from the DOM — the consumer owns removal via `@if`\n * (agnostic-atom doctrine). The close control's accessible name comes from a projected\n * `[skra-alert-close-label]` (sr-only; ADR 033 Path 2) — the \"×\" glyph is `aria-hidden`.\n */\n@Component({\n selector: 'skra-alert',\n standalone: true,\n imports: [SkraAlertIcon, SkraAlertTitle],\n templateUrl: './alert.html',\n styleUrl: './alert.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5)\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-emphasis]': 'emphasis()',\n\n // Announcement role (ADR 0052) — implicit-live role ONLY; never an explicit aria-live.\n '[attr.role]': 'liveRole()',\n\n // Smart Slots layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)\n '[attr.data-skra-has-icon]': 'hasIcon() ? \"\" : null',\n '[attr.data-skra-has-title]': 'hasTitle() ? \"\" : null',\n },\n})\nexport class SkraAlert {\n // --- Variant Surface (ADR 035) ---\n readonly intent = input<AlertIntent>('neutral');\n readonly emphasis = input<AlertEmphasis>('medium');\n\n // --- Announcement (ADR 0052) ---\n readonly live = input<AlertLive>('off');\n\n // --- Dismissal ---\n readonly dismissible = input(false, { transform: booleanAttribute });\n readonly dismissed = output<void>();\n\n // --- Smart Slots v2.0 (ADR 020) ---\n readonly iconSlot = contentChild(SkraAlertIcon);\n readonly hasIcon = computed(() => !!this.iconSlot());\n\n readonly titleSlot = contentChild(SkraAlertTitle);\n readonly hasTitle = computed(() => !!this.titleSlot());\n\n /**\n * Map `live` politeness to the implicit-live ARIA role (ADR 0052). The role\n * carries `aria-live` + `aria-atomic` implicitly; `off` → no live region.\n */\n readonly liveRole = computed<'alert' | 'status' | null>(() => {\n switch (this.live()) {\n case 'assertive':\n return 'alert';\n case 'polite':\n return 'status';\n default:\n return null;\n }\n });\n\n protected onDismiss(): void {\n this.dismissed.emit();\n }\n}\n","@if (hasIcon()) {\r\n<span class=\"skra-alert-icon\">\r\n <ng-content select=\"[skra-alert-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-alert-content\">\r\n @if (hasTitle()) {\r\n <div class=\"skra-alert-title\">\r\n <ng-content select=\"[skra-alert-title]\"></ng-content>\r\n </div>\r\n }\r\n <div class=\"skra-alert-body\">\r\n <ng-content></ng-content>\r\n </div>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-alert-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-alert-dismiss-glyph\" aria-hidden=\"true\">&times;</span>\r\n <ng-content select=\"[skra-alert-close-label]\"></ng-content>\r\n</button>\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skra-ui-alert.mjs","sources":["../../../../libs/ui/alert/src/lib/alert.directives.ts","../../../../libs/ui/alert/src/lib/alert/alert.ts","../../../../libs/ui/alert/src/lib/alert/alert.html","../../../../libs/ui/alert/src/skra-ui-alert.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n/**\n * Marker directive for the leading icon slot of `<skra-alert>`.\n * Detected via `contentChild` (ADR 020 Smart Slots v2.0) to toggle the icon\n * wrapper without emitting an empty DOM node. Feedback-local (not the button\n * lib's `[skra-start]`) to avoid a cross-lib marker dependency.\n */\n@Directive({\n selector: '[skra-alert-icon]',\n standalone: true,\n})\nexport class SkraAlertIcon {}\n\n/**\n * Marker directive for the OPTIONAL title slot of `<skra-alert>` — a short, bold\n * heading rendered above the message. Detected via `contentChild` (ADR 020) to\n * toggle the title row. It is styled bold via a typography role but is NOT a\n * semantic heading (`<h*>`): an alert title is not part of the document outline,\n * and a heading would pollute screen-reader heading navigation (especially for a\n * dynamically-injected alert). The live region announces title + body atomically.\n */\n@Directive({\n selector: '[skra-alert-title]',\n standalone: true,\n})\nexport class SkraAlertTitle {}\n\n/**\n * Marker directive for an ACTION of `<skra-alert>` — \"what to do next\" (\"Try again\").\n * Put it on each action; several are allowed and keep the consumer's order. Detected via\n * `contentChildren` (ADR 020) to render the actions region below the message only when one\n * exists. The region sits inside the content column, so it never collides with the dismiss\n * control.\n *\n * The action keeps its OWN meaning: the alert never sets or changes a projected button's\n * `intent` / `emphasis` (ADR 0059 R59.1) — a retry inside a danger alert is not a destructive\n * action. What the alert owns is the region's layout and the focus ring its actions draw on the\n * alert's fill (R59.3). Guaranteed legible on the alert's fill (ADR 0059 R59.2 — the gate\n * measures exactly these):\n *\n * | Alert emphasis | Guaranteed actions |\n * | ------------------- | --------------------------------------------------------------- |\n * | `medium` (default) | `neutral` at any emphasis; any intent at `emphasis=\"high\"` |\n * | `high` | any intent at `emphasis=\"high\"` other than the alert's intent |\n *\n * Anything else (a coloured `medium`/`low` action, a `medium`/`low` action on a `high` alert,\n * a `high` action in the alert's own intent) is unsupported. The zero-config\n * `<button skraButton skra-alert-actions>` (`neutral × high`) is guaranteed everywhere except\n * on a `neutral × high` alert. Admitted atom: `button[skraButton]`.\n *\n * Announcement: a live alert (`live=\"polite\"|\"assertive\"`) announces its whole text, action\n * labels included (the implicit `role` carries `aria-atomic`, ADR 0052) — the label tells the\n * user an action exists.\n */\n@Directive({\n selector: '[skra-alert-actions]',\n standalone: true,\n})\nexport class SkraAlertActions {}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n booleanAttribute,\n computed,\n contentChild,\n contentChildren,\n input,\n output,\n} from '@angular/core';\nimport {\n SkraAlertActions,\n SkraAlertIcon,\n SkraAlertTitle,\n} from '../alert.directives';\n\n/**\n * AlertIntent — semantic feedback meaning (ADR 035 §3.1, downward subset).\n * Excludes the action intents `primary`/`secondary` (meaningless for a status\n * message). Closed enum; extension requires an ADR 035 amendment.\n */\nexport type AlertIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\n/**\n * AlertEmphasis — visual loudness within the chosen intent (ADR 035 §3.1, subset).\n * `high` = filled banner, `medium` = soft/tinted. `low` deferred.\n */\nexport type AlertEmphasis = 'high' | 'medium';\n\n/**\n * AlertLive — screen-reader announcement politeness (ADR 0052). Maps to the\n * implicit-live ARIA role; politeness is a property of USE (static vs injected),\n * NOT of intent.\n */\nexport type AlertLive = 'off' | 'polite' | 'assertive';\n\n/**\n * `<skra-alert>` — in-content, page/section-level feedback message (Feedback/Status\n * family, ADR 0052). Serves BOTH a static notification (`live=\"off\"`, present at load)\n * and a dynamically-injected alert (`live=\"polite\"|\"assertive\"`, announced on insertion).\n *\n * SRP-distinct from `<skra-error>` (form-validation-bound, `SkraFieldContext`, error-only).\n *\n * Announcement (ADR 0052): the `live` input maps to the implicit-live ARIA role\n * (`status`/`alert`) — which carries `aria-live` + `aria-atomic` implicitly. NO explicit\n * `aria-live` is set (that would be redundant/contradictory; the `skra-error` pattern).\n *\n * Dismissal: `dismissible` renders a built-in close control that emits `(dismissed)`.\n * Forge does NOT remove itself from the DOM — the consumer owns removal via `@if`\n * (agnostic-atom doctrine). The close control's accessible name comes from a projected\n * `[skra-alert-close-label]` (sr-only; ADR 033 Path 2) — the \"×\" glyph is `aria-hidden`.\n *\n * Actions (GitHub #4, ADR 0059): mark each next-step button `[skra-alert-actions]`; they render\n * in a region below the message. The alert owns that region's layout and its focus ring, never\n * the actions' meaning — see `SkraAlertActions` for the guaranteed combinations.\n */\n@Component({\n selector: 'skra-alert',\n standalone: true,\n imports: [SkraAlertIcon, SkraAlertTitle, SkraAlertActions],\n templateUrl: './alert.html',\n styleUrl: './alert.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5)\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-emphasis]': 'emphasis()',\n\n // Announcement role (ADR 0052) — implicit-live role ONLY; never an explicit aria-live.\n '[attr.role]': 'liveRole()',\n\n // Smart Slots layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)\n '[attr.data-skra-has-icon]': 'hasIcon() ? \"\" : null',\n '[attr.data-skra-has-title]': 'hasTitle() ? \"\" : null',\n '[attr.data-skra-has-actions]': 'hasActions() ? \"\" : null',\n },\n})\nexport class SkraAlert {\n // --- Variant Surface (ADR 035) ---\n readonly intent = input<AlertIntent>('neutral');\n readonly emphasis = input<AlertEmphasis>('medium');\n\n // --- Announcement (ADR 0052) ---\n readonly live = input<AlertLive>('off');\n\n // --- Dismissal ---\n readonly dismissible = input(false, { transform: booleanAttribute });\n readonly dismissed = output<void>();\n\n // --- Smart Slots v2.0 (ADR 020) ---\n readonly iconSlot = contentChild(SkraAlertIcon);\n readonly hasIcon = computed(() => !!this.iconSlot());\n\n readonly titleSlot = contentChild(SkraAlertTitle);\n readonly hasTitle = computed(() => !!this.titleSlot());\n\n // Several actions are allowed (consumer order) — hence contentChildren, not contentChild.\n // The alert never touches their intent/emphasis (ADR 0059 R59.1); see SkraAlertActions.\n readonly actionSlots = contentChildren(SkraAlertActions);\n readonly hasActions = computed(() => this.actionSlots().length > 0);\n\n /**\n * Map `live` politeness to the implicit-live ARIA role (ADR 0052). The role\n * carries `aria-live` + `aria-atomic` implicitly; `off` → no live region.\n */\n readonly liveRole = computed<'alert' | 'status' | null>(() => {\n switch (this.live()) {\n case 'assertive':\n return 'alert';\n case 'polite':\n return 'status';\n default:\n return null;\n }\n });\n\n protected onDismiss(): void {\n this.dismissed.emit();\n }\n}\n","@if (hasIcon()) {\n<span class=\"skra-alert-icon\">\n <ng-content select=\"[skra-alert-icon]\"></ng-content>\n</span>\n}\n\n<div class=\"skra-alert-content\">\n @if (hasTitle()) {\n <div class=\"skra-alert-title\">\n <ng-content select=\"[skra-alert-title]\"></ng-content>\n </div>\n }\n <div class=\"skra-alert-body\">\n <ng-content></ng-content>\n </div>\n @if (hasActions()) {\n <div class=\"skra-alert-actions\">\n <ng-content select=\"[skra-alert-actions]\"></ng-content>\n </div>\n }\n</div>\n\n@if (dismissible()) {\n<button type=\"button\" class=\"skra-alert-dismiss\" (click)=\"onDismiss()\">\n <span class=\"skra-alert-dismiss-glyph\" aria-hidden=\"true\">&times;</span>\n <ng-content select=\"[skra-alert-close-label]\"></ng-content>\n</button>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}