@skra/ui 0.5.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.
Files changed (42) hide show
  1. package/consumer-guide/README.md +90 -85
  2. package/consumer-guide/accessible-names.md +2 -1
  3. package/consumer-guide/custom-components.md +154 -0
  4. package/consumer-guide/feedback.md +100 -0
  5. package/consumer-guide/wrapping-patterns.md +98 -90
  6. package/fesm2022/skra-ui-alert.mjs +55 -6
  7. package/fesm2022/skra-ui-alert.mjs.map +1 -1
  8. package/fesm2022/skra-ui-button.mjs +2 -2
  9. package/fesm2022/skra-ui-button.mjs.map +1 -1
  10. package/fesm2022/skra-ui-checkbox.mjs +2 -2
  11. package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
  12. package/fesm2022/skra-ui-chip.mjs +2 -2
  13. package/fesm2022/skra-ui-chip.mjs.map +1 -1
  14. package/fesm2022/skra-ui-core.mjs +30 -5
  15. package/fesm2022/skra-ui-core.mjs.map +1 -1
  16. package/fesm2022/skra-ui-input.mjs +2 -2
  17. package/fesm2022/skra-ui-input.mjs.map +1 -1
  18. package/fesm2022/skra-ui-menu.mjs +38 -14
  19. package/fesm2022/skra-ui-menu.mjs.map +1 -1
  20. package/fesm2022/skra-ui-popover.mjs +25 -9
  21. package/fesm2022/skra-ui-popover.mjs.map +1 -1
  22. package/fesm2022/skra-ui-radio.mjs +2 -2
  23. package/fesm2022/skra-ui-radio.mjs.map +1 -1
  24. package/fesm2022/skra-ui-rating-display.mjs +2 -2
  25. package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
  26. package/fesm2022/skra-ui-star-rating.mjs +2 -2
  27. package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
  28. package/fesm2022/skra-ui-switch.mjs +2 -2
  29. package/fesm2022/skra-ui-switch.mjs.map +1 -1
  30. package/fesm2022/skra-ui-toast.mjs +2 -2
  31. package/fesm2022/skra-ui-toast.mjs.map +1 -1
  32. package/fesm2022/skra-ui-tooltip.mjs +7 -2
  33. package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
  34. package/package.json +2 -2
  35. package/types/skra-ui-alert.d.ts +39 -2
  36. package/types/skra-ui-alert.d.ts.map +1 -1
  37. package/types/skra-ui-core.d.ts.map +1 -1
  38. package/types/skra-ui-menu.d.ts +18 -6
  39. package/types/skra-ui-menu.d.ts.map +1 -1
  40. package/types/skra-ui-popover.d.ts +13 -4
  41. package/types/skra-ui-popover.d.ts.map +1 -1
  42. package/types/skra-ui-tooltip.d.ts.map +1 -1
@@ -1,90 +1,98 @@
1
- # Wrapping Skra in Your Own Components
2
-
3
- > Load this for: building project-specific components on top of Skra atoms to simplify the
4
- > API down to the inputs your app actually needs. Governed by the *atoms-agnostic* doctrine +
5
- > ADR 037 (consumer owns value/ergonomics).
6
-
7
- ## Why wrap, and where the wrapper belongs
8
-
9
- Skra atoms are deliberately low-level and semantic-only — they ship a11y + tokens + binding
10
- seams, not app ergonomics. The intended consumption shape is: **your app wraps Skra atoms in
11
- higher-level components** that expose just the inputs your domain needs.
12
-
13
- The hard rule: **the wrapper lives in YOUR app (or a consumer library), never back inside
14
- `@skra/*`.** Pulling app ergonomics into the atom breaks the agnostic contract (ADR 037). If a
15
- wrapper becomes reusable across several of your apps, promote it to **your own library built ON
16
- Skra** (`@yourorg/ui`), not into Skra core.
17
-
18
- ## Pattern 1 — a field wrapper (collapse the field boilerplate)
19
-
20
- The `<skra-field>` + label + control + hint + error + binding cluster is verbose to repeat.
21
- Wrap it once:
22
-
23
- ```ts
24
- // app-text-field.component.ts (YOUR code)
25
- @Component({
26
- selector: 'app-text-field',
27
- standalone: true,
28
- imports: [SkraField, SkraInput, SkraLabelFor, SkraHint, SkraError],
29
- template: `
30
- <skra-field>
31
- <label skraLabelFor>{{ label() }}</label>
32
- <input skraInput [formField]="field()" />
33
- @if (hint()) { <skra-hint>{{ hint() }}</skra-hint> }
34
- @if (errorText()) { <skra-error>{{ errorText() }}</skra-error> }
35
- </skra-field>
36
- `,
37
- })
38
- export class AppTextField {
39
- readonly label = input.required<string>();
40
- readonly field = input.required<Field<string>>(); // your Signal Forms node type
41
- readonly hint = input<string>();
42
- readonly errorText = input<string>();
43
- }
44
- ```
45
-
46
- ```html
47
- <!-- call site: domain-minimal API -->
48
- <app-text-field label="Email" [field]="form().email" hint="We never share it." />
49
- ```
50
-
51
- **What NOT to break when wrapping:**
52
-
53
- - Don't re-implement a11y — keep the control inside `<skra-field>` so the DI context still
54
- wires `id`/`for`/`aria-describedby` (ADR 013). Don't add `aria-label` (ADR 033).
55
- - Don't introduce inline styles to theme — scope tokens with a class (ADR 021).
56
- - Keep the accessible-name path intact (the projected `<label skraLabelFor>` IS the name).
57
-
58
- ## Pattern 2 — a value-bridge adapter for class-B overlays
59
-
60
- The class-B overlays (`skra-select`, `skra-datepicker`, `skra-star-rating`, …) need the
61
- two-binding `[value]`/`(valueChange)` bridge (see `forms-and-binding.md`). If that recurs, the
62
- sanctioned shape is a **consumer-side adapter directive** that maps a form node ↔
63
- value/valueChange, so the call site goes back to one binding:
64
-
65
- ```ts
66
- // app-control.directive.ts (YOUR interop layer — a sketch)
67
- @Directive({ selector: '[appControl]', standalone: true })
68
- export class AppControl<T> {
69
- readonly appControl = input.required<Field<T>>();
70
- // read [value] from the host element + write back on (valueChange),
71
- // syncing this.appControl().value() ↔ the field node
72
- }
73
- ```
74
-
75
- ```html
76
- <skra-select [appControl]="form().country">…</skra-select>
77
- ```
78
-
79
- This adapter is **yours**, in your interop layer — it must not live in the atom (ADR 037). The
80
- friction journal calls this candidate `[skraControl]` (F-3).
81
-
82
- ## The open question — `@skra/angular-interop`? (resolved: not now)
83
-
84
- If *every* Angular consumer needs the same value-bridge adapter, there is an argument that
85
- Skra could ship an **optional, opt-in** `@skra/angular-interop` package — separate from the
86
- agnostic atoms (atoms stay pure; interop is a voluntary layer on top). **Resolved 2026-06-25
87
- (ADR 037 §7): DECLINED for now** — with one consumer and a still-iterating Signal Forms API,
88
- the bridge stays consumer-owned (Pattern 2). The trigger to revisit, then via its own ADR:
89
- several real consumers feeling the friction AND a stabilised Angular forms API (that ADR must
90
- first resolve strategy-agnosticism — Signal Forms AND Reactive via a seam, never bless one).
1
+ # Wrapping Skra in Your Own Components
2
+
3
+ > Load this for: building project-specific components on top of Skra atoms to simplify the
4
+ > API down to the inputs your app actually needs. Governed by the _atoms-agnostic_ doctrine +
5
+ > ADR 037 (consumer owns value/ergonomics).
6
+
7
+ ## Why wrap, and where the wrapper belongs
8
+
9
+ Skra atoms are deliberately low-level and semantic-only — they ship a11y + tokens + binding
10
+ seams, not app ergonomics. The intended consumption shape is: **your app wraps Skra atoms in
11
+ higher-level components** that expose just the inputs your domain needs.
12
+
13
+ The hard rule: **the wrapper lives in YOUR app (or a consumer library), never back inside
14
+ `@skra/*`.** Pulling app ergonomics into the atom breaks the agnostic contract (ADR 037). If a
15
+ wrapper becomes reusable across several of your apps, promote it to **your own library built ON
16
+ Skra** (`@yourorg/ui`), not into Skra core.
17
+
18
+ **If there is no atom to wrap** — a net-new widget Skra does not ship at all (a scrubber, a
19
+ timeline, a domain visual) — this page does not cover it. Go to `custom-components.md`, which
20
+ gives the token contract that keeps such a component on-skin, on-density and dark-mode-correct.
21
+
22
+ ## Pattern 1 — a field wrapper (collapse the field boilerplate)
23
+
24
+ The `<skra-field>` + label + control + hint + error + binding cluster is verbose to repeat.
25
+ Wrap it once:
26
+
27
+ ```ts
28
+ // app-text-field.component.ts (YOUR code)
29
+ @Component({
30
+ selector: 'app-text-field',
31
+ standalone: true,
32
+ imports: [SkraField, SkraInput, SkraLabelFor, SkraHint, SkraError],
33
+ template: `
34
+ <skra-field>
35
+ <label skraLabelFor>{{ label() }}</label>
36
+ <input skraInput [formField]="field()" />
37
+ @if (hint()) {
38
+ <skra-hint>{{ hint() }}</skra-hint>
39
+ }
40
+ @if (errorText()) {
41
+ <skra-error>{{ errorText() }}</skra-error>
42
+ }
43
+ </skra-field>
44
+ `,
45
+ })
46
+ export class AppTextField {
47
+ readonly label = input.required<string>();
48
+ readonly field = input.required<Field<string>>(); // your Signal Forms node type
49
+ readonly hint = input<string>();
50
+ readonly errorText = input<string>();
51
+ }
52
+ ```
53
+
54
+ ```html
55
+ <!-- call site: domain-minimal API -->
56
+ <app-text-field label="Email" [field]="form().email" hint="We never share it." />
57
+ ```
58
+
59
+ **What NOT to break when wrapping:**
60
+
61
+ - Don't re-implement a11y — keep the control inside `<skra-field>` so the DI context still
62
+ wires `id`/`for`/`aria-describedby` (ADR 013). Don't add `aria-label` (ADR 033).
63
+ - Don't introduce inline styles to theme — scope tokens with a class (ADR 021).
64
+ - Keep the accessible-name path intact (the projected `<label skraLabelFor>` IS the name).
65
+
66
+ ## Pattern 2 — a value-bridge adapter for class-B overlays
67
+
68
+ The class-B overlays (`skra-select`, `skra-datepicker`, `skra-star-rating`, …) need the
69
+ two-binding `[value]`/`(valueChange)` bridge (see `forms-and-binding.md`). If that recurs, the
70
+ sanctioned shape is a **consumer-side adapter directive** that maps a form node ↔
71
+ value/valueChange, so the call site goes back to one binding:
72
+
73
+ ```ts
74
+ // app-control.directive.ts (YOUR interop layer — a sketch)
75
+ @Directive({ selector: '[appControl]', standalone: true })
76
+ export class AppControl<T> {
77
+ readonly appControl = input.required<Field<T>>();
78
+ // read [value] from the host element + write back on (valueChange),
79
+ // syncing this.appControl().value() ↔ the field node
80
+ }
81
+ ```
82
+
83
+ ```html
84
+ <skra-select [appControl]="form().country">…</skra-select>
85
+ ```
86
+
87
+ This adapter is **yours**, in your interop layer — it must not live in the atom (ADR 037). The
88
+ friction journal calls this candidate `[skraControl]` (F-3).
89
+
90
+ ## The open question — `@skra/angular-interop`? (resolved: not now)
91
+
92
+ If _every_ Angular consumer needs the same value-bridge adapter, there is an argument that
93
+ Skra could ship an **optional, opt-in** `@skra/angular-interop` package — separate from the
94
+ agnostic atoms (atoms stay pure; interop is a voluntary layer on top). **Resolved 2026-06-25
95
+ (ADR 037 §7): DECLINED for now** — with one consumer and a still-iterating Signal Forms API,
96
+ the bridge stays consumer-owned (Pattern 2). The trigger to revisit, then via its own ADR:
97
+ several real consumers feeling the friction AND a stabilised Angular forms API (that ADR must
98
+ first resolve strategy-agnosticism — Signal Forms AND Reactive via a seam, never bless one).
@@ -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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"}