@skra/ui 0.4.0 → 0.6.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.
- package/consumer-guide/README.md +88 -85
- package/consumer-guide/custom-components.md +154 -0
- package/consumer-guide/wrapping-patterns.md +98 -90
- package/fesm2022/skra-ui-accordion.mjs +2 -2
- package/fesm2022/skra-ui-accordion.mjs.map +1 -1
- package/fesm2022/skra-ui-alert.mjs +2 -2
- package/fesm2022/skra-ui-alert.mjs.map +1 -1
- package/fesm2022/skra-ui-avatar.mjs.map +1 -1
- package/fesm2022/skra-ui-badge.mjs.map +1 -1
- package/fesm2022/skra-ui-button.mjs +2 -2
- package/fesm2022/skra-ui-button.mjs.map +1 -1
- package/fesm2022/skra-ui-checkbox.mjs +2 -2
- package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
- package/fesm2022/skra-ui-chip.mjs +2 -2
- package/fesm2022/skra-ui-chip.mjs.map +1 -1
- package/fesm2022/skra-ui-combobox.mjs +120 -120
- package/fesm2022/skra-ui-combobox.mjs.map +1 -1
- package/fesm2022/skra-ui-core.mjs +64 -39
- package/fesm2022/skra-ui-core.mjs.map +1 -1
- package/fesm2022/skra-ui-counter.mjs.map +1 -1
- package/fesm2022/skra-ui-datepicker.mjs +605 -190
- package/fesm2022/skra-ui-datepicker.mjs.map +1 -1
- package/fesm2022/skra-ui-dialog.mjs.map +1 -1
- package/fesm2022/skra-ui-field.mjs.map +1 -1
- package/fesm2022/skra-ui-icon.mjs.map +1 -1
- package/fesm2022/skra-ui-input.mjs +2 -2
- package/fesm2022/skra-ui-input.mjs.map +1 -1
- package/fesm2022/skra-ui-kbd.mjs.map +1 -1
- package/fesm2022/skra-ui-layout.mjs.map +1 -1
- package/fesm2022/skra-ui-link.mjs +2 -2
- package/fesm2022/skra-ui-link.mjs.map +1 -1
- package/fesm2022/skra-ui-loading-indicator.mjs.map +1 -1
- package/fesm2022/skra-ui-menu.mjs +40 -16
- package/fesm2022/skra-ui-menu.mjs.map +1 -1
- package/fesm2022/skra-ui-multi-select.mjs +94 -94
- package/fesm2022/skra-ui-multi-select.mjs.map +1 -1
- package/fesm2022/skra-ui-native-select.mjs +2 -2
- package/fesm2022/skra-ui-native-select.mjs.map +1 -1
- package/fesm2022/skra-ui-popover.mjs +25 -9
- package/fesm2022/skra-ui-popover.mjs.map +1 -1
- package/fesm2022/skra-ui-progress.mjs.map +1 -1
- package/fesm2022/skra-ui-radio.mjs +2 -2
- package/fesm2022/skra-ui-radio.mjs.map +1 -1
- package/fesm2022/skra-ui-rating-display.mjs +2 -2
- package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
- package/fesm2022/skra-ui-select.mjs +92 -92
- package/fesm2022/skra-ui-select.mjs.map +1 -1
- package/fesm2022/skra-ui-skeleton.mjs +8 -8
- package/fesm2022/skra-ui-skeleton.mjs.map +1 -1
- package/fesm2022/skra-ui-star-rating.mjs +2 -2
- package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
- package/fesm2022/skra-ui-status-dot.mjs.map +1 -1
- package/fesm2022/skra-ui-switch.mjs +2 -2
- package/fesm2022/skra-ui-switch.mjs.map +1 -1
- package/fesm2022/skra-ui-tabs.mjs +2 -2
- package/fesm2022/skra-ui-tabs.mjs.map +1 -1
- package/fesm2022/skra-ui-textarea.mjs +2 -2
- package/fesm2022/skra-ui-textarea.mjs.map +1 -1
- package/fesm2022/skra-ui-toast.mjs +2 -2
- package/fesm2022/skra-ui-toast.mjs.map +1 -1
- package/fesm2022/skra-ui-tooltip.mjs +7 -2
- package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
- package/fesm2022/skra-ui-typography.mjs.map +1 -1
- package/package.json +3 -3
- package/types/skra-ui-core.d.ts.map +1 -1
- package/types/skra-ui-datepicker.d.ts +146 -46
- package/types/skra-ui-datepicker.d.ts.map +1 -1
- package/types/skra-ui-menu.d.ts +18 -6
- package/types/skra-ui-menu.d.ts.map +1 -1
- package/types/skra-ui-popover.d.ts +13 -4
- package/types/skra-ui-popover.d.ts.map +1 -1
- package/types/skra-ui-tooltip.d.ts.map +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-status-dot.mjs","sources":["../../../../libs/ui/status-dot/src/lib/status-dot/status-dot.ts","../../../../libs/ui/status-dot/src/skra-ui-status-dot.ts"],"sourcesContent":["import {\
|
|
1
|
+
{"version":3,"file":"skra-ui-status-dot.mjs","sources":["../../../../libs/ui/status-dot/src/lib/status-dot/status-dot.ts","../../../../libs/ui/status-dot/src/skra-ui-status-dot.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\n/**\n * StatusDotIntent — the Variant Surface Intent axis (ADR 035 §3.1, the status palette subset).\n * Drops the action intents `primary`/`secondary` (those belong to interactive surfaces, not a\n * status glyph). Closed enum; extension requires an ADR 035 amendment.\n */\nexport type StatusDotIntent =\n | 'neutral'\n | 'info'\n | 'success'\n | 'warning'\n | 'danger';\n\n/**\n * StatusDotSize — the Variant Surface Size axis (ADR 035 §3.1, downward subset `sm|md|lg`).\n * `xs`/`xl` are reserved (ADR 035 §3.2) and NOT in MVP — adding them later is purely additive.\n * Unlike content-width Badge (which has no size — its size is its text), the dot has NO content,\n * so size is a genuine free variable the consumer needs (corner-of-`lg`-avatar vs inline-in-text).\n */\nexport type StatusDotSize = 'sm' | 'md' | 'lg';\n\n/**\n * `<skra-status-dot>` — a bare, small, non-interactive status/presence indicator (a coloured dot)\n * composed beside other content: an avatar corner (online/away/busy/offline), or beside a label.\n * Second resident of `libs/ui/data-display`, sibling to `<skra-avatar>` (whose corner presence-dot\n * it provides). See `adr/specs/component-status-dot-spec.md`.\n *\n * **Element, not a decorated native (ADR 012):** there is no native `<dot>`, and a bare `<span>`\n * carries no semantics and forces a colour literal. NOT a Web Component (ADR 000).\n *\n * **No content (the SRP line vs `skra-badge`):** the dot IS the glyph — no slots, no projected\n * content, no label/count. Meaning is carried by ADJACENT text the consumer owns. The defining\n * value-add over a hand-rolled span is the semantic `intent`→token-colour mapping (no hex — ADR\n * 002/023) + the size axis that tracks the avatar.\n *\n * **Non-interactive (Avatar/Badge precedent):** no focusable node, no widget role, no keyboard, no\n * outputs → State Surface all-N/A. A clickable status = `button[skraButton]` composition, not a\n * variant.\n *\n * **Accessible name (ADR 033 Path 3 — graphic host, the SkraIcon/Avatar contract):** the host\n * carries NO default ARIA. The consumer declares semantics explicitly, exactly as for\n * `<skra-icon>`/`<skra-avatar>`:\n * - decorative (Mode A, the ~90% case — dot beside visible/sr-only status text) → `aria-hidden=\"true\"`;\n * - meaningful (Mode B — the dot is the SOLE status carrier) → **`role=\"img\"` + `aria-label`/\n * `aria-labelledby` TOGETHER**. `role=\"img\"` is REQUIRED: `aria-label` on the roleless host is\n * ARIA-prohibited (axe `aria-prohibited-attr`, the Avatar Mode-B fix) and conveys no name.\n * WCAG 1.4.1 (colour-independence) cannot be enforced by the atom — the adjacent text is the\n * consumer's; the `InlineStatus`/`A11yCheck` stories carry the editorial contract. NO `ariaLabel`\n * input (ADR 033 boundary #8).\n *\n * **Look is skin-owned:** circle-vs-square is the `radius` comp token (brutal's `radius.full: 0`\n * ships a square dot automatically). The fill is the semantic `intent`→`sys.color.<intent>.base`\n * (recolour at the sys level, not a per-dot token — skin philosophy); NO `emphasis` (always filled),\n * NO `live` (a dot has no text to announce — the consumer's adjacent live text does), NO\n * `color`/`variant`/`shape` look-inputs.\n */\n@Component({\n selector: 'skra-status-dot',\n standalone: true,\n template: '',\n styleUrl: './status-dot.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var]).\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-size]': 'size()',\n },\n})\nexport class SkraStatusDot {\n /** Variant Surface Intent axis (ADR 035) — the fill colour (status palette subset). */\n readonly intent = input<StatusDotIntent>('neutral');\n\n /** Variant Surface Size axis (ADR 035) — the dot's (colored core) diameter. */\n readonly size = input<StatusDotSize>('md');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AA2BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkCG;MAcU,aAAa,CAAA;;IAEf,MAAM,GAAG,KAAK,CAAkB,SAAS;+EAAC;;IAG1C,IAAI,GAAG,KAAK,CAAgB,IAAI;6EAAC;uGAL/B,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAb,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,aAAa,uaAVd,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,gvCAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAUD,aAAa,EAAA,UAAA,EAAA,CAAA;kBAbzB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,iBAAiB,EAAA,UAAA,EACf,IAAI,EAAA,QAAA,EACN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,yBAAyB,EAAE,UAAU;AACrC,wBAAA,uBAAuB,EAAE,QAAQ;AAClC,qBAAA,EAAA,MAAA,EAAA,CAAA,gvCAAA,CAAA,EAAA;;;ACzEH;;AAEG;;;;"}
|
|
@@ -68,7 +68,7 @@ class SkraSwitch {
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
71
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraSwitch, isStandalone: true, selector: "input[type=\"checkbox\"][skraSwitch]", host: { attributes: { "role": "switch" }, listeners: { "click": "blockWhenReadonly($event)", "keydown": "blockKeyWhenReadonly($event)" }, properties: { "attr.data-skra-disabled": "context?.isDisabled() ? \"\" : null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-readonly": "context?.isReadonly() ? \"true\" : null", "attr.aria-describedby": "context?.describedByIds() ?? null" } }, ngImport: i0, template: '', isInline: true, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-background-readonly);border-color:var(--skra-comp-field-border-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
71
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraSwitch, isStandalone: true, selector: "input[type=\"checkbox\"][skraSwitch]", host: { attributes: { "role": "switch" }, listeners: { "click": "blockWhenReadonly($event)", "keydown": "blockKeyWhenReadonly($event)" }, properties: { "attr.data-skra-disabled": "context?.isDisabled() ? \"\" : null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-readonly": "context?.isReadonly() ? \"true\" : null", "attr.aria-describedby": "context?.describedByIds() ?? null" } }, ngImport: i0, template: '', isInline: true, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}@media(hover:hover)and (pointer:fine){:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-switch-background-readonly);border-color:var(--skra-comp-field-border-color-readonly);--_switch-thumb: var(--skra-comp-field-switch-thumb-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly);--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
72
72
|
}
|
|
73
73
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSwitch, decorators: [{
|
|
74
74
|
type: Component,
|
|
@@ -83,7 +83,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
83
83
|
'[attr.aria-describedby]': 'context?.describedByIds() ?? null',
|
|
84
84
|
'(click)': 'blockWhenReadonly($event)',
|
|
85
85
|
'(keydown)': 'blockKeyWhenReadonly($event)',
|
|
86
|
-
}, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-background-readonly);border-color:var(--skra-comp-field-border-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
|
|
86
|
+
}, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}@media(hover:hover)and (pointer:fine){:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-switch-background-readonly);border-color:var(--skra-comp-field-border-color-readonly);--_switch-thumb: var(--skra-comp-field-switch-thumb-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly);--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
|
|
87
87
|
}], ctorParameters: () => [] });
|
|
88
88
|
|
|
89
89
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-switch.mjs","sources":["../../../../libs/ui/switch/src/lib/switch/switch.ts","../../../../libs/ui/switch/src/skra-ui-switch.ts"],"sourcesContent":["import {\
|
|
1
|
+
{"version":3,"file":"skra-ui-switch.mjs","sources":["../../../../libs/ui/switch/src/lib/switch/switch.ts","../../../../libs/ui/switch/src/skra-ui-switch.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n effect,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * Wires a native `<input type=\"checkbox\">` to the **switch** role + skin when inside\n * `<skra-field>` (ADR 013), or standalone with no cascade. Per ADR 039/040, Forge ships\n * no `<skra-switch>` wrapper — this is a Component-on-the-native-host (`<input>` is void →\n * `template: ''`, ADR 040 §2) carrying its own `switch.scss` via Emulated encapsulation. The\n * ADR 039 revision history named this exact pattern as the future switch primitive.\n *\n * **The directive SETS `role=\"switch\"`** (it is not part of the selector) — the consumer must\n * not be asked to repeat an obvious, required ARIA role. No native HTML element produces switch\n * semantics, so `role=\"switch\"` is the legitimate ARIA mechanism (native-attr-first rule 2). The\n * browser maps the native checked state to `aria-checked` (on/off) under this role.\n *\n * <!-- inside Field -->\n * <skra-field>\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\n * <label skraLabelFor>Enable notifications</label>\n * </skra-field>\n *\n * <!-- standalone (label wraps input — no id/for needed) -->\n * <label>\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\n * Dark mode\n * </label>\n *\n * Value channel stays consumer-owned per ADR 037 (native `[checked]` + `(change)`, Reactive\n * Forms `formControlName`, Signal Forms `[formField]`, or `[(ngModel)]` — all orthogonal). Toggle\n * state is NOT reflected as `data-skra-*` (that would require Forge to observe native state,\n * violating ADR 037); the skin keys off the native `:checked` pseudo-class.\n *\n * Distinct from `skraCheckbox` (the atom-granularity split): a switch is strictly binary —\n * `role=\"switch\"` forbids `aria-checked=\"mixed\"`, so there is **no `indeterminate` input**.\n */\n@Component({\n selector: 'input[type=\"checkbox\"][skraSwitch]',\n standalone: true,\n // Void host — no <ng-content>. See ADR 040 §2.\n template: '',\n styleUrl: './switch.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).\n role: 'switch',\n '[attr.data-skra-disabled]': 'context?.isDisabled() ? \"\" : null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n // Readonly is ARIA-only (native `readonly` doesn't apply to checkboxes per HTML spec);\n // styling keys off `[aria-readonly]`. Mirrors skraCheckbox / skraRadio.\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '(click)': 'blockWhenReadonly($event)',\n '(keydown)': 'blockKeyWhenReadonly($event)',\n },\n})\nexport class SkraSwitch {\n private readonly el = inject<ElementRef<HTMLInputElement>>(ElementRef);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n constructor() {\n // Field-cascaded native properties — only bind when context is present so\n // standalone consumers retain full control of their static attributes.\n if (this.context) {\n const ctx = this.context;\n const el = this.el.nativeElement;\n effect(() => {\n el.id = ctx.fieldId();\n });\n effect(() => {\n el.disabled = ctx.isDisabled();\n });\n }\n }\n\n /**\n * Readonly enforcement — native checkbox has no `[readonly]`, so without this the\n * `aria-readonly` we announce would be a lie (the user could still toggle it).\n * `preventDefault` on `click` blocks the toggle from both pointer and Space (keyboard\n * activation dispatches a click on form controls). Mirrors the checkbox/radio guards.\n */\n protected blockWhenReadonly(event: Event): void {\n if (this.context?.isReadonly()) event.preventDefault();\n }\n\n /** Block keyboard activation (Space) when readonly; let `Tab` through. */\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\n if (this.context?.isReadonly() && event.key !== 'Tab') {\n event.preventDefault();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,UAAU,CAAA;AACJ,IAAA,EAAE,GAAG,MAAM,CAA+B,UAAU,CAAC;IAC7D,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;;;AAGE,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;AACxB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;YAChC,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;;;;AAKG;AACO,IAAA,iBAAiB,CAAC,KAAY,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE;IACxD;;AAGU,IAAA,oBAAoB,CAAC,KAAoB,EAAA;AACjD,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;YACrD,KAAK,CAAC,cAAc,EAAE;QACxB;IACF;uGAlCW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,2fAjBX,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,mzFAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,UAAU,EAAA,UAAA,EAAA,CAAA;kBArBtB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,EAAA,UAAA,EAClC,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,2BAA2B,EAAE,mCAAmC;AAChE,wBAAA,qBAAqB,EAAE,qCAAqC;;;AAG5D,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,SAAS,EAAE,2BAA2B;AACtC,wBAAA,WAAW,EAAE,8BAA8B;AAC5C,qBAAA,EAAA,MAAA,EAAA,CAAA,mzFAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
|
|
@@ -107,7 +107,7 @@ class SkraTab {
|
|
|
107
107
|
this.ctx?.select(this.value());
|
|
108
108
|
}
|
|
109
109
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
110
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraTab, isStandalone: true, selector: "button[skraTab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tab", "type": "button" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "tabId()", "attr.aria-controls": "panelId()", "attr.aria-selected": "ariaSelected()", "attr.tabindex": "tabindex()" } }, exportAs: ["skraTab"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);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);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
110
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraTab, isStandalone: true, selector: "button[skraTab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tab", "type": "button" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "tabId()", "attr.aria-controls": "panelId()", "attr.aria-selected": "ariaSelected()", "attr.tabindex": "tabindex()" } }, exportAs: ["skraTab"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);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);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}@media(hover:hover)and (pointer:fine){:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
111
111
|
}
|
|
112
112
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTab, decorators: [{
|
|
113
113
|
type: Component,
|
|
@@ -119,7 +119,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
119
119
|
'[attr.aria-selected]': 'ariaSelected()',
|
|
120
120
|
'[attr.tabindex]': 'tabindex()',
|
|
121
121
|
'(click)': 'onClick()',
|
|
122
|
-
}, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);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);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"] }]
|
|
122
|
+
}, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);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);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}@media(hover:hover)and (pointer:fine){:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"] }]
|
|
123
123
|
}], ctorParameters: () => [], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: true }] }] } });
|
|
124
124
|
|
|
125
125
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-tabs.mjs","sources":["../../../../libs/ui/tabs/src/lib/tabs/tabs-context.ts","../../../../libs/ui/tabs/src/lib/tabs/tab.ts","../../../../libs/ui/tabs/src/lib/tabs/tab-panel.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs-keyboard.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs.ts","../../../../libs/ui/tabs/src/lib/tabs/tablist.ts","../../../../libs/ui/tabs/src/skra-ui-tabs.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\r\n\r\n/** Module-global counter → a deterministic, unique id base per `[skraTabs]` instance.\r\n * Equivalent to the forms `IdGeneratorService` (ADR 013) but lib-local, so `@skra/navigation`\r\n * takes no dependency on `@skra/forms` just for id generation. Stable across SSR↔hydration\r\n * (same instantiation order yields the same ids — the standard counter technique). */\r\nlet tabsInstanceCounter = 0;\r\n\r\n/** Sanitize a consumer `value` into an id-safe fragment (no spaces / special chars). */\r\nfunction idSafe(value: string): string {\r\n return value.replace(/[^a-zA-Z0-9_-]/g, '-');\r\n}\r\n\r\n/**\r\n * DI Context provided per `[skraTabs]` instance — the ADR 013 §3.6 **non-form** Contextual-ID-Sync\r\n * bus wiring `tab` ↔ `tabpanel`. It carries **IDs + derived, read-only interaction state only**\r\n * (`selected` mirrors the consumer's `[selected]`; `activeValue` is the roving-focus position). It\r\n * **never owns value** — selection stays consumer-owned (ADR 037); a tab requests a change through\r\n * `select()`, which the coordinator implements and from which it emits `(selectedChange)`.\r\n */\r\n@Injectable()\r\nexport class SkraTabsContext {\r\n /** Unique per `[skraTabs]` — the prefix for every tab/panel id in this group. */\r\n private readonly baseId = `skra-tabs-${++tabsInstanceCounter}`;\r\n\r\n /** Mirror of the consumer's `[selected]` — drives `aria-selected` + panel visibility (read-only to children). */\r\n readonly selected = signal<string>('');\r\n /** Roving-focus position — the value of the tab that currently carries `tabindex=\"0\"` (read-only to children). */\r\n readonly activeValue = signal<string>('');\r\n /** Activation model (read-only to children). */\r\n readonly activation = signal<'automatic' | 'manual'>('automatic');\r\n\r\n tabId(value: string): string {\r\n return `${this.baseId}-tab-${idSafe(value)}`;\r\n }\r\n panelId(value: string): string {\r\n return `${this.baseId}-panel-${idSafe(value)}`;\r\n }\r\n isSelected(value: string): boolean {\r\n return this.selected() === value;\r\n }\r\n\r\n /** Coordinator-assigned: a tab/keyboard requests selection (the coordinator emits `(selectedChange)`). */\r\n select: (value: string) => void = () => undefined;\r\n /** Coordinator-assigned: the tablist forwards its `keydown` here (routed to the keyboard controller). */\r\n handleKeydown: (event: KeyboardEvent) => void = () => undefined;\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n computed,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport { SkraTabsContext } from './tabs-context';\r\nimport type { SkraTabKeyItem } from './tabs-types';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTab — a single tab, a Component on the native command host `button[skraTab]` (ADR 012/040:\r\n * a `<button>` gives Enter/Space→click + focusability for free; its implicit role is overridden to\r\n * `role=\"tab\"`, the precedent set by `button[skraMenuItem]`).\r\n *\r\n * Roving tabindex: `tabindex=\"0\"` only when this tab is the roving stop (`SkraTabsContext.activeValue`),\r\n * else `-1` — the controller (`SkraTabsKeyboard`) moves real focus. `aria-selected` reflects the\r\n * consumer-owned selection (`[selected]`), NOT the roving focus — and is the source of truth for the\r\n * selected STYLE too (CSS keys off `:host([aria-selected=\"true\"])`; no `data-skra-*`). On activation it\r\n * REQUESTS selection from the coordinator (`ctx.select`) — it never mutates selection itself (ADR 037).\r\n *\r\n * **Disabled is native-attr-first (boundary #9): the consumer sets the native `disabled` attribute** —\r\n * Forge OBSERVES it (no `disabled` input). A disabled tab is SKIPPED in the roving order (APG).\r\n */\r\n@Component({\r\n selector: 'button[skraTab]',\r\n standalone: true,\r\n exportAs: 'skraTab',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './tab.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tab',\r\n type: 'button', // never an implicit submit if the tablist sits inside a <form>\r\n '[attr.id]': 'tabId()',\r\n '[attr.aria-controls]': 'panelId()',\r\n '[attr.aria-selected]': 'ariaSelected()',\r\n '[attr.tabindex]': 'tabindex()',\r\n '(click)': 'onClick()',\r\n },\r\n})\r\nexport class SkraTab implements SkraTabKeyItem {\r\n /** Selection key — matched against `skraTabs [selected]` and the owning panel's `value`. */\r\n readonly value = input.required<string>();\r\n\r\n private readonly host = inject<ElementRef<HTMLButtonElement>>(ElementRef);\r\n private readonly ctx = inject(SkraTabsContext, { optional: true });\r\n\r\n protected readonly tabId = computed(\r\n () => this.ctx?.tabId(this.value()) ?? null,\r\n );\r\n protected readonly panelId = computed(\r\n () => this.ctx?.panelId(this.value()) ?? null,\r\n );\r\n protected readonly ariaSelected = computed(() =>\r\n this.ctx?.isSelected(this.value()) ? 'true' : 'false',\r\n );\r\n protected readonly tabindex = computed(() => {\r\n if (!this.ctx) return null; // standalone misuse — leave the native button focusable\r\n return this.ctx.activeValue() === this.value() ? '0' : '-1';\r\n });\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.ctx) {\r\n console.warn(\r\n '[skraTab] has no [skraTabs] ancestor — it is not wired to a tablist (no aria-controls / ' +\r\n 'roving / selection). Project it inside <div skraTablist> within <element skraTabs>.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n // ── SkraTabKeyItem (driven by SkraTabsKeyboard / CDK FocusKeyManager) ──\r\n focus(): void {\r\n this.host.nativeElement.focus();\r\n }\r\n /** Disabled tabs are skipped in the roving order — read live off the native attribute (no input). */\r\n isDisabled(): boolean {\r\n return this.host.nativeElement.disabled;\r\n }\r\n getValue(): string {\r\n return this.value();\r\n }\r\n\r\n protected onClick(): void {\r\n if (this.host.nativeElement.disabled) return; // belt-and-suspenders (native disabled won't fire click)\r\n this.ctx?.select(this.value());\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n computed,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport { SkraTabsContext } from './tabs-context';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTabPanel — the `role=\"tabpanel\"` for one tab, a Component on the consumer's `<div skraTabPanel>`\r\n * (ADR 040, `template: '<ng-content>'` so the panel body renders). It is focusable (`tabindex=\"0\"`, APG —\r\n * keyboard users Tab from the active tab into its content), auto-named by `aria-labelledby`→its tab, and\r\n * `hidden` when its `value` is not the selected one (removed from the a11y tree; stays in the DOM — lazy\r\n * mounting is the consumer's own `@if` on the content).\r\n */\r\n@Component({\r\n selector: '[skraTabPanel]',\r\n standalone: true,\r\n exportAs: 'skraTabPanel',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './tab-panel.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tabpanel',\r\n tabindex: '0',\r\n '[attr.id]': 'panelId()',\r\n '[attr.aria-labelledby]': 'tabId()',\r\n '[attr.hidden]': 'hidden()',\r\n },\r\n})\r\nexport class SkraTabPanel {\r\n /** Selection key — matched against the owning `button[skraTab]`'s `value`. */\r\n readonly value = input.required<string>();\r\n\r\n private readonly ctx = inject(SkraTabsContext, { optional: true });\r\n\r\n protected readonly panelId = computed(\r\n () => this.ctx?.panelId(this.value()) ?? null,\r\n );\r\n protected readonly tabId = computed(\r\n () => this.ctx?.tabId(this.value()) ?? null,\r\n );\r\n /** `''` (attribute present) when not selected → hidden; `null` (absent) when selected → shown. */\r\n protected readonly hidden = computed(() =>\r\n this.ctx?.isSelected(this.value()) ? null : '',\r\n );\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.ctx) {\r\n console.warn(\r\n '[skraTabPanel] has no [skraTabs] ancestor — it cannot be linked to a tab or shown/hidden. ' +\r\n 'Project it inside <element skraTabs>.',\r\n );\r\n }\r\n }\r\n }\r\n}\r\n","import { FocusKeyManager } from '@angular/cdk/a11y';\r\n\r\nimport type { SkraTabKeyItem } from './tabs-types';\r\n\r\n/**\r\n * SkraTabsKeyboard — the WAI-ARIA APG **Tabs** roving-tabindex keyboard model, confined to ONE file.\r\n *\r\n * This is the **only** module in `@skra/navigation` that imports `@angular/cdk` (ADR 0044 §7,\r\n * generalized library-wide 2026-06-19). It wraps CDK `FocusKeyManager` (roving REAL focus) so the\r\n * engine is swappable in one file — exactly as `SkraMenuKeyboard` does for the menu. Unlike the menu,\r\n * tabs use **horizontal** orientation (Left/Right) and **skip** disabled tabs.\r\n *\r\n * Owns: Left/Right roving (wrap), Home/End. Enter/Space (native button activation) and selection are\r\n * the coordinator's job — the controller only moves focus and reports the active tab's value.\r\n */\r\nexport class SkraTabsKeyboard {\r\n private manager?: FocusKeyManager<SkraTabKeyItem>;\r\n private items: SkraTabKeyItem[] = [];\r\n\r\n /**\r\n * (Re)build the manager from the current projected tab set. Called from an `effect` on the signal\r\n * `contentChildren` — a passed array is a static snapshot, so the manager is rebuilt whenever the\r\n * tab set changes (the documented signal↔CDK seam, mirroring `menu-keyboard.ts`).\r\n */\r\n setItems(items: readonly SkraTabKeyItem[]): void {\r\n this.items = [...items];\r\n this.manager?.destroy();\r\n this.manager = new FocusKeyManager<SkraTabKeyItem>(this.items)\r\n .withHorizontalOrientation('ltr') // Left/Right; RTL handled by the manager via the page dir\r\n .withWrap()\r\n .withHomeAndEnd()\r\n // Tabs SKIP disabled (APG): a disabled tab is not a roving stop. (Menu keeps them focusable.)\r\n .skipPredicate((tab) => tab.isDisabled());\r\n }\r\n\r\n /** Delegate Left/Right/Home/End. Enter/Space/Tab are intentionally left to the platform/coordinator. */\r\n onKeydown(event: KeyboardEvent): void {\r\n this.manager?.onKeydown(event);\r\n }\r\n\r\n /** The value of the tab the manager currently considers active (focused after `onKeydown`). */\r\n activeValue(): string | undefined {\r\n return this.manager?.activeItem?.getValue();\r\n }\r\n\r\n /** Sync the manager's active index to a value WITHOUT moving focus (after a click / on init). */\r\n setActive(value: string): void {\r\n const index = this.items.findIndex((tab) => tab.getValue() === value);\r\n if (index >= 0) this.manager?.updateActiveItem(index);\r\n }\r\n\r\n /** The first non-disabled tab's value (the roving stop when nothing is selected) — APG. */\r\n firstEnabledValue(): string | undefined {\r\n return this.items.find((tab) => !tab.isDisabled())?.getValue();\r\n }\r\n\r\n hasValue(value: string): boolean {\r\n return this.items.some((tab) => tab.getValue() === value);\r\n }\r\n\r\n destroy(): void {\r\n this.manager?.destroy();\r\n this.manager = undefined;\r\n }\r\n}\r\n","import {\r\n DestroyRef,\r\n Directive,\r\n contentChildren,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\n\r\nimport { SkraTab } from './tab';\r\nimport { SkraTabPanel } from './tab-panel';\r\nimport { SkraTabsContext } from './tabs-context';\r\nimport { SkraTabsKeyboard } from './tabs-keyboard';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTabs — the WAI-ARIA APG **Tabs** coordinator. A directive on a wrapping element that holds a\r\n * `[skraTablist]` (the `role=\"tablist\"` with its `button[skraTab]` children) and the\r\n * `[skraTabPanel]` panels as DI descendants. It provides `SkraTabsContext` (the ADR 013 §3.6 non-form\r\n * Contextual-ID-Sync bus), owns the consumer-facing `[selected]` / `(selectedChange)` (controlled,\r\n * ADR 037 — NO internal selection state) and `[activation]`, and drives the roving-tabindex keyboard\r\n * (`SkraTabsKeyboard` → CDK `FocusKeyManager`).\r\n *\r\n * <div skraTabs [selected]=\"tab()\" (selectedChange)=\"tab.set($event)\">\r\n * <div skraTablist aria-label=\"Account\">\r\n * <button skraTab value=\"profile\">Profile</button>\r\n * <button skraTab value=\"security\">Security</button>\r\n * </div>\r\n * <div skraTabPanel value=\"profile\">…</div>\r\n * <div skraTabPanel value=\"security\">…</div>\r\n * </div>\r\n *\r\n * Selection is consumer-owned: a click / Enter / Space / (automatic) arrow emits `(selectedChange)`;\r\n * the visible selection updates when the consumer round-trips `[selected]`. The roving focus position\r\n * (`tabindex=\"0\"`) is component-owned UI state — it moves immediately, independent of `[selected]`.\r\n *\r\n * Full contract: adr/specs/component-tabs-spec.md.\r\n */\r\n@Directive({\r\n selector: '[skraTabs]',\r\n standalone: true,\r\n exportAs: 'skraTabs',\r\n providers: [SkraTabsContext],\r\n})\r\nexport class SkraTabs {\r\n /** Consumer-owned selection key (matches a tab's `value`); '' / no-match → nothing selected (ADR 037). */\r\n readonly selected = input<string>('');\r\n /** Automatic (selection follows roving focus) | manual (Enter/Space selects). */\r\n readonly activation = input<'automatic' | 'manual'>('automatic');\r\n /** Fires ONLY on user activation — never on a programmatic `[selected]` change. */\r\n readonly selectedChange = output<string>();\r\n\r\n private readonly ctx = inject(SkraTabsContext);\r\n private readonly tabs = contentChildren(SkraTab, { descendants: true });\r\n private readonly panels = contentChildren(SkraTabPanel, {\r\n descendants: true,\r\n });\r\n private readonly keyboard = new SkraTabsKeyboard();\r\n\r\n constructor() {\r\n // Wire the context bus (a tab requests selection; the tablist forwards keydown).\r\n this.ctx.select = (value) => this.selectTab(value);\r\n this.ctx.handleKeydown = (event) => this.onTablistKeydown(event);\r\n\r\n // Mirror inputs → context (read-only to children).\r\n effect(() => this.ctx.selected.set(this.selected()));\r\n effect(() => this.ctx.activation.set(this.activation()));\r\n\r\n // (Re)build the keyboard from the projected tab set and (re)seat the roving stop whenever the tab\r\n // set or the selection changes. Rebuilding the manager for a handful of tabs is trivial.\r\n effect(() => {\r\n this.keyboard.setItems(this.tabs());\r\n this.reseat();\r\n });\r\n\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n effect(() => this.warnMismatches());\r\n }\r\n\r\n inject(DestroyRef).onDestroy(() => this.keyboard.destroy());\r\n }\r\n\r\n /** Seat the roving stop (`tabindex=\"0\"`) on a real, enabled tab: the selected one if valid, else the\r\n * first enabled tab (APG — the tablist must always have exactly one tab stop). */\r\n private reseat(): void {\r\n const sel = this.selected();\r\n const next = this.keyboard.hasValue(sel)\r\n ? sel\r\n : (this.keyboard.firstEnabledValue() ?? '');\r\n this.ctx.activeValue.set(next);\r\n if (next) this.keyboard.setActive(next);\r\n }\r\n\r\n /** A tab was activated (click / Enter / Space / automatic arrow). Move the roving stop immediately\r\n * (UI state), then REQUEST selection from the consumer — never mutate selection internally (ADR 037). */\r\n private selectTab(value: string): void {\r\n this.ctx.activeValue.set(value);\r\n this.keyboard.setActive(value);\r\n if (this.selected() === value) return; // idempotent — no redundant output\r\n this.selectedChange.emit(value);\r\n }\r\n\r\n private onTablistKeydown(event: KeyboardEvent): void {\r\n const before = this.keyboard.activeValue();\r\n this.keyboard.onKeydown(event);\r\n const after = this.keyboard.activeValue();\r\n if (after && after !== before) {\r\n this.ctx.activeValue.set(after); // roving moved (focus already on the new tab)\r\n if (this.ctx.activation() === 'automatic') this.selectTab(after);\r\n }\r\n }\r\n\r\n /** Dev-only nudge: every tab needs a panel of the same `value`, and vice-versa (aria-controls / -labelledby). */\r\n private warnMismatches(): void {\r\n const tabValues = new Set(this.tabs().map((t) => t.value()));\r\n const panelValues = new Set(this.panels().map((p) => p.value()));\r\n for (const v of tabValues) {\r\n if (!panelValues.has(v))\r\n console.warn(\r\n `[skraTabs] tab value=\"${v}\" has no matching [skraTabPanel] — its aria-controls points to a missing panel.`,\r\n );\r\n }\r\n for (const v of panelValues) {\r\n if (!tabValues.has(v))\r\n console.warn(\r\n `[skraTabs] panel value=\"${v}\" has no matching button[skraTab] — it will never be revealed.`,\r\n );\r\n }\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n inject,\r\n} from '@angular/core';\r\n\r\nimport { SkraTabsContext } from './tabs-context';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTablist — the `role=\"tablist\"` container, a Component on the consumer's `<div skraTablist>`\r\n * (ADR 040, `template: '<ng-content>'` so the projected `button[skraTab]` children render). It carries\r\n * the rail styling and forwards its `keydown` to the coordinator's roving keyboard (`SkraTabsKeyboard`)\r\n * via the `SkraTabsContext` bus. Name it for AT with consumer `aria-label`/`aria-labelledby` (ADR 033).\r\n */\r\n@Component({\r\n selector: '[skraTablist]',\r\n standalone: true,\r\n exportAs: 'skraTablist',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './tablist.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tablist',\r\n 'aria-orientation': 'horizontal',\r\n '(keydown)': 'onKeydown($event)',\r\n },\r\n})\r\nexport class SkraTablist {\r\n private readonly ctx = inject(SkraTabsContext, { optional: true });\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.ctx) {\r\n console.warn(\r\n '[skraTablist] has no [skraTabs] ancestor — its tabs cannot be keyboard-navigated. ' +\r\n 'Wrap the tablist + panels in <element skraTabs>.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n protected onKeydown(event: KeyboardEvent): void {\r\n this.ctx?.handleKeydown(event);\r\n }\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-tabs.mjs","sources":["../../../../libs/ui/tabs/src/lib/tabs/tabs-context.ts","../../../../libs/ui/tabs/src/lib/tabs/tab.ts","../../../../libs/ui/tabs/src/lib/tabs/tab-panel.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs-keyboard.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs.ts","../../../../libs/ui/tabs/src/lib/tabs/tablist.ts","../../../../libs/ui/tabs/src/skra-ui-tabs.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\n\n/** Module-global counter → a deterministic, unique id base per `[skraTabs]` instance.\n * Equivalent to the forms `IdGeneratorService` (ADR 013) but lib-local, so `@skra/navigation`\n * takes no dependency on `@skra/forms` just for id generation. Stable across SSR↔hydration\n * (same instantiation order yields the same ids — the standard counter technique). */\nlet tabsInstanceCounter = 0;\n\n/** Sanitize a consumer `value` into an id-safe fragment (no spaces / special chars). */\nfunction idSafe(value: string): string {\n return value.replace(/[^a-zA-Z0-9_-]/g, '-');\n}\n\n/**\n * DI Context provided per `[skraTabs]` instance — the ADR 013 §3.6 **non-form** Contextual-ID-Sync\n * bus wiring `tab` ↔ `tabpanel`. It carries **IDs + derived, read-only interaction state only**\n * (`selected` mirrors the consumer's `[selected]`; `activeValue` is the roving-focus position). It\n * **never owns value** — selection stays consumer-owned (ADR 037); a tab requests a change through\n * `select()`, which the coordinator implements and from which it emits `(selectedChange)`.\n */\n@Injectable()\nexport class SkraTabsContext {\n /** Unique per `[skraTabs]` — the prefix for every tab/panel id in this group. */\n private readonly baseId = `skra-tabs-${++tabsInstanceCounter}`;\n\n /** Mirror of the consumer's `[selected]` — drives `aria-selected` + panel visibility (read-only to children). */\n readonly selected = signal<string>('');\n /** Roving-focus position — the value of the tab that currently carries `tabindex=\"0\"` (read-only to children). */\n readonly activeValue = signal<string>('');\n /** Activation model (read-only to children). */\n readonly activation = signal<'automatic' | 'manual'>('automatic');\n\n tabId(value: string): string {\n return `${this.baseId}-tab-${idSafe(value)}`;\n }\n panelId(value: string): string {\n return `${this.baseId}-panel-${idSafe(value)}`;\n }\n isSelected(value: string): boolean {\n return this.selected() === value;\n }\n\n /** Coordinator-assigned: a tab/keyboard requests selection (the coordinator emits `(selectedChange)`). */\n select: (value: string) => void = () => undefined;\n /** Coordinator-assigned: the tablist forwards its `keydown` here (routed to the keyboard controller). */\n handleKeydown: (event: KeyboardEvent) => void = () => undefined;\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\n\nimport { SkraTabsContext } from './tabs-context';\nimport type { SkraTabKeyItem } from './tabs-types';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTab — a single tab, a Component on the native command host `button[skraTab]` (ADR 012/040:\n * a `<button>` gives Enter/Space→click + focusability for free; its implicit role is overridden to\n * `role=\"tab\"`, the precedent set by `button[skraMenuItem]`).\n *\n * Roving tabindex: `tabindex=\"0\"` only when this tab is the roving stop (`SkraTabsContext.activeValue`),\n * else `-1` — the controller (`SkraTabsKeyboard`) moves real focus. `aria-selected` reflects the\n * consumer-owned selection (`[selected]`), NOT the roving focus — and is the source of truth for the\n * selected STYLE too (CSS keys off `:host([aria-selected=\"true\"])`; no `data-skra-*`). On activation it\n * REQUESTS selection from the coordinator (`ctx.select`) — it never mutates selection itself (ADR 037).\n *\n * **Disabled is native-attr-first (boundary #9): the consumer sets the native `disabled` attribute** —\n * Forge OBSERVES it (no `disabled` input). A disabled tab is SKIPPED in the roving order (APG).\n */\n@Component({\n selector: 'button[skraTab]',\n standalone: true,\n exportAs: 'skraTab',\n template: '<ng-content></ng-content>',\n styleUrl: './tab.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tab',\n type: 'button', // never an implicit submit if the tablist sits inside a <form>\n '[attr.id]': 'tabId()',\n '[attr.aria-controls]': 'panelId()',\n '[attr.aria-selected]': 'ariaSelected()',\n '[attr.tabindex]': 'tabindex()',\n '(click)': 'onClick()',\n },\n})\nexport class SkraTab implements SkraTabKeyItem {\n /** Selection key — matched against `skraTabs [selected]` and the owning panel's `value`. */\n readonly value = input.required<string>();\n\n private readonly host = inject<ElementRef<HTMLButtonElement>>(ElementRef);\n private readonly ctx = inject(SkraTabsContext, { optional: true });\n\n protected readonly tabId = computed(\n () => this.ctx?.tabId(this.value()) ?? null,\n );\n protected readonly panelId = computed(\n () => this.ctx?.panelId(this.value()) ?? null,\n );\n protected readonly ariaSelected = computed(() =>\n this.ctx?.isSelected(this.value()) ? 'true' : 'false',\n );\n protected readonly tabindex = computed(() => {\n if (!this.ctx) return null; // standalone misuse — leave the native button focusable\n return this.ctx.activeValue() === this.value() ? '0' : '-1';\n });\n\n constructor() {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n if (!this.ctx) {\n console.warn(\n '[skraTab] has no [skraTabs] ancestor — it is not wired to a tablist (no aria-controls / ' +\n 'roving / selection). Project it inside <div skraTablist> within <element skraTabs>.',\n );\n }\n }\n }\n\n // ── SkraTabKeyItem (driven by SkraTabsKeyboard / CDK FocusKeyManager) ──\n focus(): void {\n this.host.nativeElement.focus();\n }\n /** Disabled tabs are skipped in the roving order — read live off the native attribute (no input). */\n isDisabled(): boolean {\n return this.host.nativeElement.disabled;\n }\n getValue(): string {\n return this.value();\n }\n\n protected onClick(): void {\n if (this.host.nativeElement.disabled) return; // belt-and-suspenders (native disabled won't fire click)\n this.ctx?.select(this.value());\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\n\nimport { SkraTabsContext } from './tabs-context';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTabPanel — the `role=\"tabpanel\"` for one tab, a Component on the consumer's `<div skraTabPanel>`\n * (ADR 040, `template: '<ng-content>'` so the panel body renders). It is focusable (`tabindex=\"0\"`, APG —\n * keyboard users Tab from the active tab into its content), auto-named by `aria-labelledby`→its tab, and\n * `hidden` when its `value` is not the selected one (removed from the a11y tree; stays in the DOM — lazy\n * mounting is the consumer's own `@if` on the content).\n */\n@Component({\n selector: '[skraTabPanel]',\n standalone: true,\n exportAs: 'skraTabPanel',\n template: '<ng-content></ng-content>',\n styleUrl: './tab-panel.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tabpanel',\n tabindex: '0',\n '[attr.id]': 'panelId()',\n '[attr.aria-labelledby]': 'tabId()',\n '[attr.hidden]': 'hidden()',\n },\n})\nexport class SkraTabPanel {\n /** Selection key — matched against the owning `button[skraTab]`'s `value`. */\n readonly value = input.required<string>();\n\n private readonly ctx = inject(SkraTabsContext, { optional: true });\n\n protected readonly panelId = computed(\n () => this.ctx?.panelId(this.value()) ?? null,\n );\n protected readonly tabId = computed(\n () => this.ctx?.tabId(this.value()) ?? null,\n );\n /** `''` (attribute present) when not selected → hidden; `null` (absent) when selected → shown. */\n protected readonly hidden = computed(() =>\n this.ctx?.isSelected(this.value()) ? null : '',\n );\n\n constructor() {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n if (!this.ctx) {\n console.warn(\n '[skraTabPanel] has no [skraTabs] ancestor — it cannot be linked to a tab or shown/hidden. ' +\n 'Project it inside <element skraTabs>.',\n );\n }\n }\n }\n}\n","import { FocusKeyManager } from '@angular/cdk/a11y';\n\nimport type { SkraTabKeyItem } from './tabs-types';\n\n/**\n * SkraTabsKeyboard — the WAI-ARIA APG **Tabs** roving-tabindex keyboard model, confined to ONE file.\n *\n * This is the **only** module in `@skra/navigation` that imports `@angular/cdk` (ADR 0044 §7,\n * generalized library-wide 2026-06-19). It wraps CDK `FocusKeyManager` (roving REAL focus) so the\n * engine is swappable in one file — exactly as `SkraMenuKeyboard` does for the menu. Unlike the menu,\n * tabs use **horizontal** orientation (Left/Right) and **skip** disabled tabs.\n *\n * Owns: Left/Right roving (wrap), Home/End. Enter/Space (native button activation) and selection are\n * the coordinator's job — the controller only moves focus and reports the active tab's value.\n */\nexport class SkraTabsKeyboard {\n private manager?: FocusKeyManager<SkraTabKeyItem>;\n private items: SkraTabKeyItem[] = [];\n\n /**\n * (Re)build the manager from the current projected tab set. Called from an `effect` on the signal\n * `contentChildren` — a passed array is a static snapshot, so the manager is rebuilt whenever the\n * tab set changes (the documented signal↔CDK seam, mirroring `menu-keyboard.ts`).\n */\n setItems(items: readonly SkraTabKeyItem[]): void {\n this.items = [...items];\n this.manager?.destroy();\n this.manager = new FocusKeyManager<SkraTabKeyItem>(this.items)\n .withHorizontalOrientation('ltr') // Left/Right; RTL handled by the manager via the page dir\n .withWrap()\n .withHomeAndEnd()\n // Tabs SKIP disabled (APG): a disabled tab is not a roving stop. (Menu keeps them focusable.)\n .skipPredicate((tab) => tab.isDisabled());\n }\n\n /** Delegate Left/Right/Home/End. Enter/Space/Tab are intentionally left to the platform/coordinator. */\n onKeydown(event: KeyboardEvent): void {\n this.manager?.onKeydown(event);\n }\n\n /** The value of the tab the manager currently considers active (focused after `onKeydown`). */\n activeValue(): string | undefined {\n return this.manager?.activeItem?.getValue();\n }\n\n /** Sync the manager's active index to a value WITHOUT moving focus (after a click / on init). */\n setActive(value: string): void {\n const index = this.items.findIndex((tab) => tab.getValue() === value);\n if (index >= 0) this.manager?.updateActiveItem(index);\n }\n\n /** The first non-disabled tab's value (the roving stop when nothing is selected) — APG. */\n firstEnabledValue(): string | undefined {\n return this.items.find((tab) => !tab.isDisabled())?.getValue();\n }\n\n hasValue(value: string): boolean {\n return this.items.some((tab) => tab.getValue() === value);\n }\n\n destroy(): void {\n this.manager?.destroy();\n this.manager = undefined;\n }\n}\n","import {\n DestroyRef,\n Directive,\n contentChildren,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\n\nimport { SkraTab } from './tab';\nimport { SkraTabPanel } from './tab-panel';\nimport { SkraTabsContext } from './tabs-context';\nimport { SkraTabsKeyboard } from './tabs-keyboard';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTabs — the WAI-ARIA APG **Tabs** coordinator. A directive on a wrapping element that holds a\n * `[skraTablist]` (the `role=\"tablist\"` with its `button[skraTab]` children) and the\n * `[skraTabPanel]` panels as DI descendants. It provides `SkraTabsContext` (the ADR 013 §3.6 non-form\n * Contextual-ID-Sync bus), owns the consumer-facing `[selected]` / `(selectedChange)` (controlled,\n * ADR 037 — NO internal selection state) and `[activation]`, and drives the roving-tabindex keyboard\n * (`SkraTabsKeyboard` → CDK `FocusKeyManager`).\n *\n * <div skraTabs [selected]=\"tab()\" (selectedChange)=\"tab.set($event)\">\n * <div skraTablist aria-label=\"Account\">\n * <button skraTab value=\"profile\">Profile</button>\n * <button skraTab value=\"security\">Security</button>\n * </div>\n * <div skraTabPanel value=\"profile\">…</div>\n * <div skraTabPanel value=\"security\">…</div>\n * </div>\n *\n * Selection is consumer-owned: a click / Enter / Space / (automatic) arrow emits `(selectedChange)`;\n * the visible selection updates when the consumer round-trips `[selected]`. The roving focus position\n * (`tabindex=\"0\"`) is component-owned UI state — it moves immediately, independent of `[selected]`.\n *\n * Full contract: adr/specs/component-tabs-spec.md.\n */\n@Directive({\n selector: '[skraTabs]',\n standalone: true,\n exportAs: 'skraTabs',\n providers: [SkraTabsContext],\n})\nexport class SkraTabs {\n /** Consumer-owned selection key (matches a tab's `value`); '' / no-match → nothing selected (ADR 037). */\n readonly selected = input<string>('');\n /** Automatic (selection follows roving focus) | manual (Enter/Space selects). */\n readonly activation = input<'automatic' | 'manual'>('automatic');\n /** Fires ONLY on user activation — never on a programmatic `[selected]` change. */\n readonly selectedChange = output<string>();\n\n private readonly ctx = inject(SkraTabsContext);\n private readonly tabs = contentChildren(SkraTab, { descendants: true });\n private readonly panels = contentChildren(SkraTabPanel, {\n descendants: true,\n });\n private readonly keyboard = new SkraTabsKeyboard();\n\n constructor() {\n // Wire the context bus (a tab requests selection; the tablist forwards keydown).\n this.ctx.select = (value) => this.selectTab(value);\n this.ctx.handleKeydown = (event) => this.onTablistKeydown(event);\n\n // Mirror inputs → context (read-only to children).\n effect(() => this.ctx.selected.set(this.selected()));\n effect(() => this.ctx.activation.set(this.activation()));\n\n // (Re)build the keyboard from the projected tab set and (re)seat the roving stop whenever the tab\n // set or the selection changes. Rebuilding the manager for a handful of tabs is trivial.\n effect(() => {\n this.keyboard.setItems(this.tabs());\n this.reseat();\n });\n\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n effect(() => this.warnMismatches());\n }\n\n inject(DestroyRef).onDestroy(() => this.keyboard.destroy());\n }\n\n /** Seat the roving stop (`tabindex=\"0\"`) on a real, enabled tab: the selected one if valid, else the\n * first enabled tab (APG — the tablist must always have exactly one tab stop). */\n private reseat(): void {\n const sel = this.selected();\n const next = this.keyboard.hasValue(sel)\n ? sel\n : (this.keyboard.firstEnabledValue() ?? '');\n this.ctx.activeValue.set(next);\n if (next) this.keyboard.setActive(next);\n }\n\n /** A tab was activated (click / Enter / Space / automatic arrow). Move the roving stop immediately\n * (UI state), then REQUEST selection from the consumer — never mutate selection internally (ADR 037). */\n private selectTab(value: string): void {\n this.ctx.activeValue.set(value);\n this.keyboard.setActive(value);\n if (this.selected() === value) return; // idempotent — no redundant output\n this.selectedChange.emit(value);\n }\n\n private onTablistKeydown(event: KeyboardEvent): void {\n const before = this.keyboard.activeValue();\n this.keyboard.onKeydown(event);\n const after = this.keyboard.activeValue();\n if (after && after !== before) {\n this.ctx.activeValue.set(after); // roving moved (focus already on the new tab)\n if (this.ctx.activation() === 'automatic') this.selectTab(after);\n }\n }\n\n /** Dev-only nudge: every tab needs a panel of the same `value`, and vice-versa (aria-controls / -labelledby). */\n private warnMismatches(): void {\n const tabValues = new Set(this.tabs().map((t) => t.value()));\n const panelValues = new Set(this.panels().map((p) => p.value()));\n for (const v of tabValues) {\n if (!panelValues.has(v))\n console.warn(\n `[skraTabs] tab value=\"${v}\" has no matching [skraTabPanel] — its aria-controls points to a missing panel.`,\n );\n }\n for (const v of panelValues) {\n if (!tabValues.has(v))\n console.warn(\n `[skraTabs] panel value=\"${v}\" has no matching button[skraTab] — it will never be revealed.`,\n );\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\n\nimport { SkraTabsContext } from './tabs-context';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTablist — the `role=\"tablist\"` container, a Component on the consumer's `<div skraTablist>`\n * (ADR 040, `template: '<ng-content>'` so the projected `button[skraTab]` children render). It carries\n * the rail styling and forwards its `keydown` to the coordinator's roving keyboard (`SkraTabsKeyboard`)\n * via the `SkraTabsContext` bus. Name it for AT with consumer `aria-label`/`aria-labelledby` (ADR 033).\n */\n@Component({\n selector: '[skraTablist]',\n standalone: true,\n exportAs: 'skraTablist',\n template: '<ng-content></ng-content>',\n styleUrl: './tablist.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tablist',\n 'aria-orientation': 'horizontal',\n '(keydown)': 'onKeydown($event)',\n },\n})\nexport class SkraTablist {\n private readonly ctx = inject(SkraTabsContext, { optional: true });\n\n constructor() {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n if (!this.ctx) {\n console.warn(\n '[skraTablist] has no [skraTabs] ancestor — its tabs cannot be keyboard-navigated. ' +\n 'Wrap the tablist + panels in <element skraTabs>.',\n );\n }\n }\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n this.ctx?.handleKeydown(event);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -53,7 +53,7 @@ class SkraTextarea {
|
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
56
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraTextarea, isStandalone: true, selector: "textarea[skraTextarea]", host: { properties: { "attr.aria-describedby": "context?.describedByIds() ?? null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-required": "context?.isRequired() ? \"true\" : null" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
56
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraTextarea, isStandalone: true, selector: "textarea[skraTextarea]", host: { properties: { "attr.aria-describedby": "context?.describedByIds() ?? null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-required": "context?.isRequired() ? \"true\" : null" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}@media(hover:hover)and (pointer:fine){:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
57
57
|
}
|
|
58
58
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTextarea, decorators: [{
|
|
59
59
|
type: Component,
|
|
@@ -67,7 +67,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
67
67
|
// `aria-disabled` duplicate. Readonly styling keys off `:read-only`.
|
|
68
68
|
// Driven imperatively below, NOT as host bindings — see the constructor
|
|
69
69
|
// note on standalone attribute ownership.
|
|
70
|
-
}, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
|
|
70
|
+
}, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}@media(hover:hover)and (pointer:fine){:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
|
|
71
71
|
}], ctorParameters: () => [] });
|
|
72
72
|
|
|
73
73
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-textarea.mjs","sources":["../../../../libs/ui/textarea/src/lib/textarea/textarea.ts","../../../../libs/ui/textarea/src/lib/auto-resize/auto-resize.directive.ts","../../../../libs/ui/textarea/src/skra-ui-textarea.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n effect,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * `textarea[skraTextarea]` — multiline text atom. Per ADR 040 this is a\n * Component-on-a-native-host carrying its own host-scoped CSS (`textarea.scss`)\n * via Emulated encapsulation, replacing the ADR 038 slice branch.\n *\n * `<textarea>` is a content-bearing host (its value is its text content), so the\n * template MUST be `<ng-content>` — `template: ''` would discard the consumer's\n * initial text. See ADR 040 §2.\n *\n * Sibling atom to SkraInput — split per atom-granularity rule (memory\n * `feedback_atom_granularity.md`): textarea has capabilities `<input>` does not\n * (multi-line content, native `rows` / `cols`, autosize composition via the\n * sibling `[skraAutoResize]` directive).\n *\n * <skra-field>\n * <label skraLabelFor>Bio</label>\n * <textarea skraTextarea skraAutoResize rows=\"3\"></textarea>\n * </skra-field>\n *\n * <!-- standalone: native implicit label (wrapping) — no id/for needed -->\n * <label>Notes <textarea skraTextarea></textarea></label>\n *\n * Native `rows` / `cols` remain the consumer-facing sizing primitives — Forge\n * does not duplicate them as Angular inputs (boundary #9 native-attr-first).\n *\n * `SkraFieldContext` is injected `{ optional: true }` (ADR 013 §3.7) — same\n * posture as SkraInput / SkraCheckbox. Standalone, the atom renders the skin\n * only and the consumer owns every attribute, including the accessible name.\n */\n@Component({\n selector: 'textarea[skraTextarea]',\n standalone: true,\n // Content-bearing host — see ADR 040 §2.\n template: '<ng-content></ng-content>',\n styleUrl: './textarea.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // ARIA relationships — Skra-owned, present only while a field cascades them.\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n '[attr.aria-required]': 'context?.isRequired() ? \"true\" : null',\n // Availability — native attrs only (native-attr-first, boundary #9).\n // <textarea> supports native `readonly`/`disabled`; NO `aria-readonly`/\n // `aria-disabled` duplicate. Readonly styling keys off `:read-only`.\n // Driven imperatively below, NOT as host bindings — see the constructor\n // note on standalone attribute ownership.\n },\n})\nexport class SkraTextarea {\n private readonly el = inject<ElementRef<HTMLTextAreaElement>>(ElementRef);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n constructor() {\n const el = this.el.nativeElement;\n\n // Field-cascaded native properties — only bind when context is present so\n // standalone consumers retain full control of their static attributes.\n // Mirrors SkraInput / SkraCheckbox.\n if (this.context) {\n const ctx = this.context;\n effect(() => {\n el.id = ctx.fieldId();\n });\n effect(() => {\n el.disabled = ctx.isDisabled();\n });\n effect(() => {\n el.readOnly = ctx.isReadonly();\n });\n }\n }\n}\n","import { Directive } from '@angular/core';\
|
|
1
|
+
{"version":3,"file":"skra-ui-textarea.mjs","sources":["../../../../libs/ui/textarea/src/lib/textarea/textarea.ts","../../../../libs/ui/textarea/src/lib/auto-resize/auto-resize.directive.ts","../../../../libs/ui/textarea/src/skra-ui-textarea.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n effect,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * `textarea[skraTextarea]` — multiline text atom. Per ADR 040 this is a\n * Component-on-a-native-host carrying its own host-scoped CSS (`textarea.scss`)\n * via Emulated encapsulation, replacing the ADR 038 slice branch.\n *\n * `<textarea>` is a content-bearing host (its value is its text content), so the\n * template MUST be `<ng-content>` — `template: ''` would discard the consumer's\n * initial text. See ADR 040 §2.\n *\n * Sibling atom to SkraInput — split per atom-granularity rule (memory\n * `feedback_atom_granularity.md`): textarea has capabilities `<input>` does not\n * (multi-line content, native `rows` / `cols`, autosize composition via the\n * sibling `[skraAutoResize]` directive).\n *\n * <skra-field>\n * <label skraLabelFor>Bio</label>\n * <textarea skraTextarea skraAutoResize rows=\"3\"></textarea>\n * </skra-field>\n *\n * <!-- standalone: native implicit label (wrapping) — no id/for needed -->\n * <label>Notes <textarea skraTextarea></textarea></label>\n *\n * Native `rows` / `cols` remain the consumer-facing sizing primitives — Forge\n * does not duplicate them as Angular inputs (boundary #9 native-attr-first).\n *\n * `SkraFieldContext` is injected `{ optional: true }` (ADR 013 §3.7) — same\n * posture as SkraInput / SkraCheckbox. Standalone, the atom renders the skin\n * only and the consumer owns every attribute, including the accessible name.\n */\n@Component({\n selector: 'textarea[skraTextarea]',\n standalone: true,\n // Content-bearing host — see ADR 040 §2.\n template: '<ng-content></ng-content>',\n styleUrl: './textarea.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // ARIA relationships — Skra-owned, present only while a field cascades them.\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n '[attr.aria-required]': 'context?.isRequired() ? \"true\" : null',\n // Availability — native attrs only (native-attr-first, boundary #9).\n // <textarea> supports native `readonly`/`disabled`; NO `aria-readonly`/\n // `aria-disabled` duplicate. Readonly styling keys off `:read-only`.\n // Driven imperatively below, NOT as host bindings — see the constructor\n // note on standalone attribute ownership.\n },\n})\nexport class SkraTextarea {\n private readonly el = inject<ElementRef<HTMLTextAreaElement>>(ElementRef);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n constructor() {\n const el = this.el.nativeElement;\n\n // Field-cascaded native properties — only bind when context is present so\n // standalone consumers retain full control of their static attributes.\n // Mirrors SkraInput / SkraCheckbox.\n if (this.context) {\n const ctx = this.context;\n effect(() => {\n el.id = ctx.fieldId();\n });\n effect(() => {\n el.disabled = ctx.isDisabled();\n });\n effect(() => {\n el.readOnly = ctx.isReadonly();\n });\n }\n }\n}\n","import { Directive } from '@angular/core';\n\n/**\n * Marker directive enabling content-driven sizing on a native form control via\n * the modern CSS `field-sizing: content` declaration shipped from the skin's\n * global utilities layer (`tokens/skins/skra/utilities.scss`).\n *\n * <textarea skraTextarea skraAutoResize rows=\"2\"></textarea>\n * <input skraInput skraAutoResize type=\"text\" />\n *\n * Composition-over-configuration: the host opts in by adding the attribute,\n * not by toggling a boolean Angular input. The directive has no host bindings,\n * no DI, and no template — its sole job is to make the selector available at\n * Angular's compilation stage; CSS does the rest.\n *\n * Wide selector (textarea + input) reflects that `field-sizing: content` is a\n * native CSS capability for both: textarea grows in block-size with rows,\n * input grows in inline-size with content width.\n */\n@Directive({\n selector: 'textarea[skraAutoResize], input[skraAutoResize]',\n standalone: true,\n})\nexport class SkraAutoResizeDirective {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;MAqBU,YAAY,CAAA;AACN,IAAA,EAAE,GAAG,MAAM,CAAkC,UAAU,CAAC;IAChE,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;;;;AAKhC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;YACxB,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;uGAtBW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAY,ySAhBb,2BAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,whDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAgB1B,YAAY,EAAA,UAAA,EAAA,CAAA;kBApBxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,UAAA,EACtB,IAAI,EAAA,QAAA,EAEN,2BAA2B,EAAA,eAAA,EAEpB,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,qBAAqB,EAAE,qCAAqC;AAC5D,wBAAA,sBAAsB,EAAE,uCAAuC;;;;;;AAMhE,qBAAA,EAAA,MAAA,EAAA,CAAA,whDAAA,CAAA,EAAA;;;ACvDH;;;;;;;;;;;;;;;;AAgBG;MAKU,uBAAuB,CAAA;uGAAvB,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAvB,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iDAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAvB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAJnC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,iDAAiD;AAC3D,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;ACtBD;;AAEG;;;;"}
|
|
@@ -114,7 +114,7 @@ class SkraToast {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraToast, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
117
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraToast, isStandalone: true, selector: "skra-toast", 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 }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { listeners: { "mouseenter": "pause()", "mouseleave": "resume()", "focusin": "pause()", "focusout": "resume()" }, properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-emphasis": "emphasis()", "attr.data-skra-has-icon": "hasIcon() ? \"\" : null" } }, queries: [{ propertyName: "iconSlot", first: true, predicate: SkraToastIcon, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "contentRef", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-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-toast-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-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}.skra-toast-dismiss:hover{opacity:.7}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
117
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraToast, isStandalone: true, selector: "skra-toast", 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 }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { listeners: { "mouseenter": "pause()", "mouseleave": "resume()", "focusin": "pause()", "focusout": "resume()" }, properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-emphasis": "emphasis()", "attr.data-skra-has-icon": "hasIcon() ? \"\" : null" } }, queries: [{ propertyName: "iconSlot", first: true, predicate: SkraToastIcon, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "contentRef", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-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-toast-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-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-toast-dismiss:hover{opacity:.7}}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
118
118
|
}
|
|
119
119
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraToast, decorators: [{
|
|
120
120
|
type: Component,
|
|
@@ -130,7 +130,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
130
130
|
'(mouseleave)': 'resume()',
|
|
131
131
|
'(focusin)': 'pause()',
|
|
132
132
|
'(focusout)': 'resume()',
|
|
133
|
-
}, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-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-toast-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-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}.skra-toast-dismiss:hover{opacity:.7}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"] }]
|
|
133
|
+
}, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-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-toast-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-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-toast-dismiss:hover{opacity:.7}}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"] }]
|
|
134
134
|
}], ctorParameters: () => [], 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 }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", 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(() => SkraToastIcon), { isSignal: true }] }], contentRef: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }] } });
|
|
135
135
|
|
|
136
136
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-toast.mjs","sources":["../../../../libs/ui/toast/src/lib/toast.directives.ts","../../../../libs/ui/toast/src/lib/toast/toast-announcer.ts","../../../../libs/ui/toast/src/lib/toast/toast.ts","../../../../libs/ui/toast/src/lib/toast/toast.html","../../../../libs/ui/toast/src/lib/toast/toast-region.ts","../../../../libs/ui/toast/src/lib/toast/toast-region.html","../../../../libs/ui/toast/src/skra-ui-toast.ts"],"sourcesContent":["import { Directive } from '@angular/core';\r\n\r\n/**\r\n * Marker directive for the leading icon slot of `<skra-toast>`.\r\n * Detected via `contentChild` (ADR 020 Smart Slots v2.0) to toggle the icon\r\n * wrapper without emitting an empty DOM node. Feedback-local (not the button\r\n * lib's `[skra-start]`) to avoid a cross-lib marker dependency — mirrors\r\n * `[skra-alert-icon]` / `[skra-badge-icon]`.\r\n */\r\n@Directive({\r\n selector: '[skra-toast-icon]',\r\n standalone: true,\r\n})\r\nexport class SkraToastIcon {}\r\n","import { InjectionToken } from '@angular/core';\r\n\r\n/**\r\n * Politeness routed to the toast region's role-only announcer (ADR 0052 §7).\r\n * `off` never reaches the announcer (no announcement), so the seam only carries\r\n * the two announced levels.\r\n */\r\nexport type SkraToastPoliteness = 'polite' | 'assertive';\r\n\r\n/**\r\n * The ADR 0052 §7 announcement seam. Provided by `<skra-toast-region>` and injected\r\n * (optionally) by each projected `<skra-toast>`. The toast pushes its message text on\r\n * appearance; the region writes it into the matching PERSISTENT, role-only announcer\r\n * (`role=\"status\"` for polite / `role=\"alert\"` for assertive) — never a role/`aria-live`\r\n * on the ephemeral toast host. This is why a live region pre-exists the content it\r\n * announces (WCAG 4.1.3): the announcers are rendered from the region's first render.\r\n *\r\n * Narrow seam (like `SkraSelectPanel` / `SkraFieldContext`): the toast depends on the\r\n * interface, not the concrete region. Content-projected toasts inject from their DECLARED\r\n * parent element (= the region), the same DI mechanism as `SkraFieldContext` (ADR 013).\r\n */\r\nexport interface SkraToastAnnouncer {\r\n /** Announce `text` at the given politeness by writing it into the matching live region. */\r\n announce(text: string, politeness: SkraToastPoliteness): void;\r\n}\r\n\r\nexport const SKRA_TOAST_ANNOUNCER = new InjectionToken<SkraToastAnnouncer>(\r\n 'SKRA_TOAST_ANNOUNCER',\r\n);\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n ElementRef,\r\n ViewEncapsulation,\r\n afterNextRender,\r\n booleanAttribute,\r\n computed,\r\n contentChild,\r\n inject,\r\n input,\r\n output,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { SkraToastIcon } from '../toast.directives';\r\nimport {\r\n SKRA_TOAST_ANNOUNCER,\r\n type SkraToastPoliteness,\r\n} from './toast-announcer';\r\n\r\n/**\r\n * ToastIntent — semantic feedback meaning (ADR 035 §3.1, downward subset). Excludes the\r\n * action intents `primary`/`secondary`. Same enum as Alert/Badge.\r\n */\r\nexport type ToastIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\r\n\r\n/** ToastEmphasis — `high` = filled, `medium` = soft. `low` deferred (ADR 035 §3.1). */\r\nexport type ToastEmphasis = 'high' | 'medium';\r\n\r\n/**\r\n * ToastLive — screen-reader announcement politeness (ADR 0052). For Toast the politeness\r\n * is routed to the REGION's announcer (ADR 0052 §7); it does NOT set a role on this host.\r\n * Default `polite` (toasts are always dynamically presented — ADR 0052 §4). `assertive`\r\n * for error toasts, set explicitly by the consumer — NEVER auto-derived from `intent`.\r\n */\r\nexport type ToastLive = 'off' | 'polite' | 'assertive';\r\n\r\n/**\r\n * `<skra-toast>` — an ephemeral, auto-dismissing feedback message rendered inside a\r\n * `<skra-toast-region>` top-layer stack (Feedback/Status family, ADR 0052; Tier 2 overlay,\r\n * ADR 0044). Visually an Alert (intent×emphasis seam, 4th consumer) with a timer.\r\n *\r\n * Announcement (ADR 0052 §7): this host carries NO `role`/`aria-live`. On appearance the\r\n * toast pushes its message text into the region's persistent role-only announcer via the\r\n * injected `SkraToastAnnouncer`, at the politeness of `live` (`off` → no announcement).\r\n *\r\n * Auto-dismiss (WCAG 2.2.1): after `duration` ms the toast emits `(dismissed)`. The timer\r\n * PAUSES on hover and on focus-within and resumes with the remaining time; `duration=0`\r\n * disables it (persistent — pair with `dismissible`). Forge does NOT self-remove — the\r\n * consumer removes the model from its array on `(dismissed)` (agnostic doctrine; the Alert\r\n * precedent). `(dismissed)` is the single removal channel (timer elapse OR close control).\r\n */\r\n@Component({\r\n selector: 'skra-toast',\r\n standalone: true,\r\n imports: [SkraToastIcon],\r\n templateUrl: './toast.html',\r\n styleUrl: './toast.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var])\r\n '[attr.data-skra-intent]': 'intent()',\r\n '[attr.data-skra-emphasis]': 'emphasis()',\r\n // Smart Slot layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)\r\n '[attr.data-skra-has-icon]': 'hasIcon() ? \"\" : null',\r\n // NO `role` / NO `aria-live` here — the region announces (ADR 0052 §7).\r\n // Pause/resume the auto-dismiss timer on hover + focus (WCAG 2.2.1 Timing Adjustable).\r\n '(mouseenter)': 'pause()',\r\n '(mouseleave)': 'resume()',\r\n '(focusin)': 'pause()',\r\n '(focusout)': 'resume()',\r\n },\r\n})\r\nexport class SkraToast {\r\n // --- Variant Surface (ADR 035) ---\r\n readonly intent = input<ToastIntent>('neutral');\r\n readonly emphasis = input<ToastEmphasis>('medium');\r\n\r\n // --- Announcement (ADR 0052 §7) ---\r\n readonly live = input<ToastLive>('polite');\r\n\r\n // --- Auto-dismiss + dismissal ---\r\n readonly duration = input<number>(5000);\r\n readonly dismissible = input(false, { transform: booleanAttribute });\r\n readonly dismissed = output<void>();\r\n\r\n // --- Smart Slots v2.0 (ADR 020) ---\r\n readonly iconSlot = contentChild(SkraToastIcon);\r\n readonly hasIcon = computed(() => !!this.iconSlot());\r\n\r\n /** The message column — its text is the announcement (excludes the icon + sr-only close label). */\r\n private readonly contentRef =\r\n viewChild.required<ElementRef<HTMLElement>>('content');\r\n\r\n private readonly announcer = inject(SKRA_TOAST_ANNOUNCER, {\r\n optional: true,\r\n });\r\n\r\n private timerId: ReturnType<typeof setTimeout> | null = null;\r\n private remaining = 0;\r\n private startedAt = 0;\r\n\r\n constructor() {\r\n afterNextRender(() => {\r\n // Announce on appearance (browser-only; projected content is present post-render).\r\n const live = this.live();\r\n if (live !== 'off' && this.announcer) {\r\n const text = this.contentRef().nativeElement.textContent?.trim() ?? '';\r\n if (text) this.announcer.announce(text, live as SkraToastPoliteness);\r\n }\r\n // Start the auto-dismiss countdown (timers are browser-only — SSR-safe by construction).\r\n this.remaining = this.duration();\r\n this.start();\r\n });\r\n inject(DestroyRef).onDestroy(() => this.clear());\r\n }\r\n\r\n protected onDismiss(): void {\r\n this.clear();\r\n this.dismissed.emit();\r\n }\r\n\r\n /** Pause the countdown, banking the remaining time (WCAG 2.2.1). */\r\n protected pause(): void {\r\n if (this.timerId === null) return;\r\n clearTimeout(this.timerId);\r\n this.timerId = null;\r\n this.remaining -= Date.now() - this.startedAt;\r\n }\r\n\r\n /** Resume the countdown with the banked remaining time. */\r\n protected resume(): void {\r\n if (this.timerId !== null) return;\r\n this.start();\r\n }\r\n\r\n private start(): void {\r\n if (this.remaining <= 0) return; // duration=0 (or fully elapsed) → persistent\r\n this.startedAt = Date.now();\r\n this.timerId = setTimeout(() => {\r\n this.timerId = null;\r\n this.dismissed.emit();\r\n }, this.remaining);\r\n }\r\n\r\n private clear(): void {\r\n if (this.timerId !== null) {\r\n clearTimeout(this.timerId);\r\n this.timerId = null;\r\n }\r\n }\r\n}\r\n","@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n afterRenderEffect,\r\n contentChildren,\r\n input,\r\n signal,\r\n viewChild,\r\n} from '@angular/core';\r\nimport { SkraToast } from './toast';\r\nimport {\r\n SKRA_TOAST_ANNOUNCER,\r\n type SkraToastAnnouncer,\r\n type SkraToastPoliteness,\r\n} from './toast-announcer';\r\n\r\n/**\r\n * ToastPlacement — viewport corner, logical (RTL-correct). `block-start`/`block-end` = the\r\n * top/bottom edge; `inline-start`/`center`/`inline-end` = the horizontal position.\r\n */\r\nexport type ToastPlacement =\r\n | 'block-start inline-start'\r\n | 'block-start center'\r\n | 'block-start inline-end'\r\n | 'block-end inline-start'\r\n | 'block-end center'\r\n | 'block-end inline-end';\r\n\r\n/**\r\n * `<skra-toast-region>` — the persistent, app-root manager for `<skra-toast>` (ADR 0044 §7\r\n * non-anchored top-layer; ADR 0052 §7 announcer). Place ONCE near the app root; the consumer\r\n * projects its own `@for` of toast models into it and owns the array (agnostic doctrine —\r\n * a `ToastService` push/remove helper is a consumer recipe, NOT shipped here).\r\n *\r\n * Two mechanisms:\r\n * - Announcement (ADR 0052 §7): provides `SkraToastAnnouncer` + renders TWO persistent,\r\n * visually-hidden, role-only announcers (`role=\"status\"` polite / `role=\"alert\"` assertive).\r\n * A toast pushes its text on appearance; identical repeated messages re-announce via a\r\n * clear-then-set across two frames (forces a live-region mutation).\r\n * - Top layer (ADR 0044 §7): a SINGLE `popover=\"manual\"` stack (not `auto` — no light-dismiss /\r\n * Escape collapse; not N popovers). Shown when non-empty; RE-ASSERTS top-layer order on each\r\n * addition (`hidePopover()`+`showPopover()`) so a toast raised over an open modal `<dialog>`\r\n * paints above it. Paint-only — never moves focus, never disturbs the dialog. Zero z-index.\r\n */\r\n@Component({\r\n selector: 'skra-toast-region',\r\n standalone: true,\r\n templateUrl: './toast-region.html',\r\n styleUrl: './toast-region.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n '[attr.data-skra-placement]': 'placement()',\r\n },\r\n providers: [{ provide: SKRA_TOAST_ANNOUNCER, useExisting: SkraToastRegion }],\r\n})\r\nexport class SkraToastRegion implements SkraToastAnnouncer {\r\n readonly placement = input<ToastPlacement>('block-end inline-end');\r\n\r\n /** The two persistent role-only announcer buffers (ADR 0052 §7). */\r\n protected readonly politeMsg = signal('');\r\n protected readonly assertiveMsg = signal('');\r\n\r\n private readonly toasts = contentChildren(SkraToast);\r\n private readonly stackEl =\r\n viewChild.required<ElementRef<HTMLElement>>('stack');\r\n\r\n /** Tracked locally — jsdom/SSR have no `:popover-open`; never read it back. */\r\n private shown = false;\r\n private prevCount = 0;\r\n\r\n constructor() {\r\n // Browser-only (afterRender family never runs on the server — SSR-safe, O-18). Reads the\r\n // contentChildren signal so it re-runs whenever the visible toast set changes.\r\n afterRenderEffect(() => {\r\n // Re-assert keys on the COUNT, not toast identity: a remove+add in the SAME change-detection\r\n // tick keeps `n` unchanged and skips the re-assert, so the new toast would not be raised above\r\n // an already-open modal. Accepted for the auto-dismiss MVP (paint-only; announcement is\r\n // unaffected); the cross-browser top-layer pass folds into O-9 (spec Open Question 3).\r\n const n = this.toasts().length;\r\n const stack = this.stackEl().nativeElement;\r\n if (n > 0) {\r\n if (n > this.prevCount && this.shown) {\r\n // Re-assert top-layer order on additions (ADR 0044 §7) — drop then re-add to the top.\r\n stack.hidePopover?.();\r\n this.shown = false;\r\n }\r\n if (!this.shown) {\r\n stack.showPopover?.();\r\n this.shown = true;\r\n }\r\n } else if (this.shown) {\r\n stack.hidePopover?.();\r\n this.shown = false;\r\n }\r\n this.prevCount = n;\r\n });\r\n }\r\n\r\n /**\r\n * ADR 0052 §7 — write `text` into the matching persistent announcer. Clear-then-set across two\r\n * animation frames so a repeated IDENTICAL message still mutates the live region and re-announces\r\n * (the \"repeated action\" case). `off` toasts never call this.\r\n */\r\n announce(text: string, politeness: SkraToastPoliteness): void {\r\n const target =\r\n politeness === 'assertive' ? this.assertiveMsg : this.politeMsg;\r\n target.set('');\r\n requestAnimationFrame(() => requestAnimationFrame(() => target.set(text)));\r\n }\r\n}\r\n","<div class=\"skra-toast-stack\" popover=\"manual\" #stack>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!--\r\n ADR 0052 §7 — two PERSISTENT, role-only live announcers, held in normal flow (NOT inside the\r\n popover, so they are pre-armed and announce regardless of the stack's shown/paint state).\r\n role=\"status\" carries aria-live=polite + aria-atomic; role=\"alert\" carries assertive + atomic\r\n (implicitly — no explicit aria-live, ADR 0052 rule 2). Each holds one message at a time.\r\n-->\r\n<div class=\"skra-sr-only\" role=\"status\">{{ politeMsg() }}</div>\r\n<div class=\"skra-sr-only\" role=\"alert\">{{ assertiveMsg() }}</div>\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-toast.mjs","sources":["../../../../libs/ui/toast/src/lib/toast.directives.ts","../../../../libs/ui/toast/src/lib/toast/toast-announcer.ts","../../../../libs/ui/toast/src/lib/toast/toast.ts","../../../../libs/ui/toast/src/lib/toast/toast.html","../../../../libs/ui/toast/src/lib/toast/toast-region.ts","../../../../libs/ui/toast/src/lib/toast/toast-region.html","../../../../libs/ui/toast/src/skra-ui-toast.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n/**\n * Marker directive for the leading icon slot of `<skra-toast>`.\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 — mirrors\n * `[skra-alert-icon]` / `[skra-badge-icon]`.\n */\n@Directive({\n selector: '[skra-toast-icon]',\n standalone: true,\n})\nexport class SkraToastIcon {}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Politeness routed to the toast region's role-only announcer (ADR 0052 §7).\n * `off` never reaches the announcer (no announcement), so the seam only carries\n * the two announced levels.\n */\nexport type SkraToastPoliteness = 'polite' | 'assertive';\n\n/**\n * The ADR 0052 §7 announcement seam. Provided by `<skra-toast-region>` and injected\n * (optionally) by each projected `<skra-toast>`. The toast pushes its message text on\n * appearance; the region writes it into the matching PERSISTENT, role-only announcer\n * (`role=\"status\"` for polite / `role=\"alert\"` for assertive) — never a role/`aria-live`\n * on the ephemeral toast host. This is why a live region pre-exists the content it\n * announces (WCAG 4.1.3): the announcers are rendered from the region's first render.\n *\n * Narrow seam (like `SkraSelectPanel` / `SkraFieldContext`): the toast depends on the\n * interface, not the concrete region. Content-projected toasts inject from their DECLARED\n * parent element (= the region), the same DI mechanism as `SkraFieldContext` (ADR 013).\n */\nexport interface SkraToastAnnouncer {\n /** Announce `text` at the given politeness by writing it into the matching live region. */\n announce(text: string, politeness: SkraToastPoliteness): void;\n}\n\nexport const SKRA_TOAST_ANNOUNCER = new InjectionToken<SkraToastAnnouncer>(\n 'SKRA_TOAST_ANNOUNCER',\n);\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n ViewEncapsulation,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n output,\n viewChild,\n} from '@angular/core';\nimport { SkraToastIcon } from '../toast.directives';\nimport {\n SKRA_TOAST_ANNOUNCER,\n type SkraToastPoliteness,\n} from './toast-announcer';\n\n/**\n * ToastIntent — semantic feedback meaning (ADR 035 §3.1, downward subset). Excludes the\n * action intents `primary`/`secondary`. Same enum as Alert/Badge.\n */\nexport type ToastIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\n/** ToastEmphasis — `high` = filled, `medium` = soft. `low` deferred (ADR 035 §3.1). */\nexport type ToastEmphasis = 'high' | 'medium';\n\n/**\n * ToastLive — screen-reader announcement politeness (ADR 0052). For Toast the politeness\n * is routed to the REGION's announcer (ADR 0052 §7); it does NOT set a role on this host.\n * Default `polite` (toasts are always dynamically presented — ADR 0052 §4). `assertive`\n * for error toasts, set explicitly by the consumer — NEVER auto-derived from `intent`.\n */\nexport type ToastLive = 'off' | 'polite' | 'assertive';\n\n/**\n * `<skra-toast>` — an ephemeral, auto-dismissing feedback message rendered inside a\n * `<skra-toast-region>` top-layer stack (Feedback/Status family, ADR 0052; Tier 2 overlay,\n * ADR 0044). Visually an Alert (intent×emphasis seam, 4th consumer) with a timer.\n *\n * Announcement (ADR 0052 §7): this host carries NO `role`/`aria-live`. On appearance the\n * toast pushes its message text into the region's persistent role-only announcer via the\n * injected `SkraToastAnnouncer`, at the politeness of `live` (`off` → no announcement).\n *\n * Auto-dismiss (WCAG 2.2.1): after `duration` ms the toast emits `(dismissed)`. The timer\n * PAUSES on hover and on focus-within and resumes with the remaining time; `duration=0`\n * disables it (persistent — pair with `dismissible`). Forge does NOT self-remove — the\n * consumer removes the model from its array on `(dismissed)` (agnostic doctrine; the Alert\n * precedent). `(dismissed)` is the single removal channel (timer elapse OR close control).\n */\n@Component({\n selector: 'skra-toast',\n standalone: true,\n imports: [SkraToastIcon],\n templateUrl: './toast.html',\n styleUrl: './toast.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var])\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-emphasis]': 'emphasis()',\n // Smart Slot layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)\n '[attr.data-skra-has-icon]': 'hasIcon() ? \"\" : null',\n // NO `role` / NO `aria-live` here — the region announces (ADR 0052 §7).\n // Pause/resume the auto-dismiss timer on hover + focus (WCAG 2.2.1 Timing Adjustable).\n '(mouseenter)': 'pause()',\n '(mouseleave)': 'resume()',\n '(focusin)': 'pause()',\n '(focusout)': 'resume()',\n },\n})\nexport class SkraToast {\n // --- Variant Surface (ADR 035) ---\n readonly intent = input<ToastIntent>('neutral');\n readonly emphasis = input<ToastEmphasis>('medium');\n\n // --- Announcement (ADR 0052 §7) ---\n readonly live = input<ToastLive>('polite');\n\n // --- Auto-dismiss + dismissal ---\n readonly duration = input<number>(5000);\n readonly dismissible = input(false, { transform: booleanAttribute });\n readonly dismissed = output<void>();\n\n // --- Smart Slots v2.0 (ADR 020) ---\n readonly iconSlot = contentChild(SkraToastIcon);\n readonly hasIcon = computed(() => !!this.iconSlot());\n\n /** The message column — its text is the announcement (excludes the icon + sr-only close label). */\n private readonly contentRef =\n viewChild.required<ElementRef<HTMLElement>>('content');\n\n private readonly announcer = inject(SKRA_TOAST_ANNOUNCER, {\n optional: true,\n });\n\n private timerId: ReturnType<typeof setTimeout> | null = null;\n private remaining = 0;\n private startedAt = 0;\n\n constructor() {\n afterNextRender(() => {\n // Announce on appearance (browser-only; projected content is present post-render).\n const live = this.live();\n if (live !== 'off' && this.announcer) {\n const text = this.contentRef().nativeElement.textContent?.trim() ?? '';\n if (text) this.announcer.announce(text, live as SkraToastPoliteness);\n }\n // Start the auto-dismiss countdown (timers are browser-only — SSR-safe by construction).\n this.remaining = this.duration();\n this.start();\n });\n inject(DestroyRef).onDestroy(() => this.clear());\n }\n\n protected onDismiss(): void {\n this.clear();\n this.dismissed.emit();\n }\n\n /** Pause the countdown, banking the remaining time (WCAG 2.2.1). */\n protected pause(): void {\n if (this.timerId === null) return;\n clearTimeout(this.timerId);\n this.timerId = null;\n this.remaining -= Date.now() - this.startedAt;\n }\n\n /** Resume the countdown with the banked remaining time. */\n protected resume(): void {\n if (this.timerId !== null) return;\n this.start();\n }\n\n private start(): void {\n if (this.remaining <= 0) return; // duration=0 (or fully elapsed) → persistent\n this.startedAt = Date.now();\n this.timerId = setTimeout(() => {\n this.timerId = null;\n this.dismissed.emit();\n }, this.remaining);\n }\n\n private clear(): void {\n if (this.timerId !== null) {\n clearTimeout(this.timerId);\n this.timerId = null;\n }\n }\n}\n","@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n afterRenderEffect,\n contentChildren,\n input,\n signal,\n viewChild,\n} from '@angular/core';\nimport { SkraToast } from './toast';\nimport {\n SKRA_TOAST_ANNOUNCER,\n type SkraToastAnnouncer,\n type SkraToastPoliteness,\n} from './toast-announcer';\n\n/**\n * ToastPlacement — viewport corner, logical (RTL-correct). `block-start`/`block-end` = the\n * top/bottom edge; `inline-start`/`center`/`inline-end` = the horizontal position.\n */\nexport type ToastPlacement =\n | 'block-start inline-start'\n | 'block-start center'\n | 'block-start inline-end'\n | 'block-end inline-start'\n | 'block-end center'\n | 'block-end inline-end';\n\n/**\n * `<skra-toast-region>` — the persistent, app-root manager for `<skra-toast>` (ADR 0044 §7\n * non-anchored top-layer; ADR 0052 §7 announcer). Place ONCE near the app root; the consumer\n * projects its own `@for` of toast models into it and owns the array (agnostic doctrine —\n * a `ToastService` push/remove helper is a consumer recipe, NOT shipped here).\n *\n * Two mechanisms:\n * - Announcement (ADR 0052 §7): provides `SkraToastAnnouncer` + renders TWO persistent,\n * visually-hidden, role-only announcers (`role=\"status\"` polite / `role=\"alert\"` assertive).\n * A toast pushes its text on appearance; identical repeated messages re-announce via a\n * clear-then-set across two frames (forces a live-region mutation).\n * - Top layer (ADR 0044 §7): a SINGLE `popover=\"manual\"` stack (not `auto` — no light-dismiss /\n * Escape collapse; not N popovers). Shown when non-empty; RE-ASSERTS top-layer order on each\n * addition (`hidePopover()`+`showPopover()`) so a toast raised over an open modal `<dialog>`\n * paints above it. Paint-only — never moves focus, never disturbs the dialog. Zero z-index.\n */\n@Component({\n selector: 'skra-toast-region',\n standalone: true,\n templateUrl: './toast-region.html',\n styleUrl: './toast-region.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n '[attr.data-skra-placement]': 'placement()',\n },\n providers: [{ provide: SKRA_TOAST_ANNOUNCER, useExisting: SkraToastRegion }],\n})\nexport class SkraToastRegion implements SkraToastAnnouncer {\n readonly placement = input<ToastPlacement>('block-end inline-end');\n\n /** The two persistent role-only announcer buffers (ADR 0052 §7). */\n protected readonly politeMsg = signal('');\n protected readonly assertiveMsg = signal('');\n\n private readonly toasts = contentChildren(SkraToast);\n private readonly stackEl =\n viewChild.required<ElementRef<HTMLElement>>('stack');\n\n /** Tracked locally — jsdom/SSR have no `:popover-open`; never read it back. */\n private shown = false;\n private prevCount = 0;\n\n constructor() {\n // Browser-only (afterRender family never runs on the server — SSR-safe, O-18). Reads the\n // contentChildren signal so it re-runs whenever the visible toast set changes.\n afterRenderEffect(() => {\n // Re-assert keys on the COUNT, not toast identity: a remove+add in the SAME change-detection\n // tick keeps `n` unchanged and skips the re-assert, so the new toast would not be raised above\n // an already-open modal. Accepted for the auto-dismiss MVP (paint-only; announcement is\n // unaffected); the cross-browser top-layer pass folds into O-9 (spec Open Question 3).\n const n = this.toasts().length;\n const stack = this.stackEl().nativeElement;\n if (n > 0) {\n if (n > this.prevCount && this.shown) {\n // Re-assert top-layer order on additions (ADR 0044 §7) — drop then re-add to the top.\n stack.hidePopover?.();\n this.shown = false;\n }\n if (!this.shown) {\n stack.showPopover?.();\n this.shown = true;\n }\n } else if (this.shown) {\n stack.hidePopover?.();\n this.shown = false;\n }\n this.prevCount = n;\n });\n }\n\n /**\n * ADR 0052 §7 — write `text` into the matching persistent announcer. Clear-then-set across two\n * animation frames so a repeated IDENTICAL message still mutates the live region and re-announces\n * (the \"repeated action\" case). `off` toasts never call this.\n */\n announce(text: string, politeness: SkraToastPoliteness): void {\n const target =\n politeness === 'assertive' ? this.assertiveMsg : this.politeMsg;\n target.set('');\n requestAnimationFrame(() => requestAnimationFrame(() => target.set(text)));\n }\n}\n","<div class=\"skra-toast-stack\" popover=\"manual\" #stack>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!--\r\n ADR 0052 §7 — two PERSISTENT, role-only live announcers, held in normal flow (NOT inside the\r\n popover, so they are pre-armed and announce regardless of the stack's shown/paint state).\r\n role=\"status\" carries aria-live=polite + aria-atomic; role=\"alert\" carries assertive + atomic\r\n (implicitly — no explicit aria-live, ADR 0052 rule 2). Each holds one message at a time.\r\n-->\r\n<div class=\"skra-sr-only\" role=\"status\">{{ politeMsg() }}</div>\r\n<div class=\"skra-sr-only\" role=\"alert\">{{ assertiveMsg() }}</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|