@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.
Files changed (72) hide show
  1. package/consumer-guide/README.md +88 -85
  2. package/consumer-guide/custom-components.md +154 -0
  3. package/consumer-guide/wrapping-patterns.md +98 -90
  4. package/fesm2022/skra-ui-accordion.mjs +2 -2
  5. package/fesm2022/skra-ui-accordion.mjs.map +1 -1
  6. package/fesm2022/skra-ui-alert.mjs +2 -2
  7. package/fesm2022/skra-ui-alert.mjs.map +1 -1
  8. package/fesm2022/skra-ui-avatar.mjs.map +1 -1
  9. package/fesm2022/skra-ui-badge.mjs.map +1 -1
  10. package/fesm2022/skra-ui-button.mjs +2 -2
  11. package/fesm2022/skra-ui-button.mjs.map +1 -1
  12. package/fesm2022/skra-ui-checkbox.mjs +2 -2
  13. package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
  14. package/fesm2022/skra-ui-chip.mjs +2 -2
  15. package/fesm2022/skra-ui-chip.mjs.map +1 -1
  16. package/fesm2022/skra-ui-combobox.mjs +120 -120
  17. package/fesm2022/skra-ui-combobox.mjs.map +1 -1
  18. package/fesm2022/skra-ui-core.mjs +64 -39
  19. package/fesm2022/skra-ui-core.mjs.map +1 -1
  20. package/fesm2022/skra-ui-counter.mjs.map +1 -1
  21. package/fesm2022/skra-ui-datepicker.mjs +605 -190
  22. package/fesm2022/skra-ui-datepicker.mjs.map +1 -1
  23. package/fesm2022/skra-ui-dialog.mjs.map +1 -1
  24. package/fesm2022/skra-ui-field.mjs.map +1 -1
  25. package/fesm2022/skra-ui-icon.mjs.map +1 -1
  26. package/fesm2022/skra-ui-input.mjs +2 -2
  27. package/fesm2022/skra-ui-input.mjs.map +1 -1
  28. package/fesm2022/skra-ui-kbd.mjs.map +1 -1
  29. package/fesm2022/skra-ui-layout.mjs.map +1 -1
  30. package/fesm2022/skra-ui-link.mjs +2 -2
  31. package/fesm2022/skra-ui-link.mjs.map +1 -1
  32. package/fesm2022/skra-ui-loading-indicator.mjs.map +1 -1
  33. package/fesm2022/skra-ui-menu.mjs +40 -16
  34. package/fesm2022/skra-ui-menu.mjs.map +1 -1
  35. package/fesm2022/skra-ui-multi-select.mjs +94 -94
  36. package/fesm2022/skra-ui-multi-select.mjs.map +1 -1
  37. package/fesm2022/skra-ui-native-select.mjs +2 -2
  38. package/fesm2022/skra-ui-native-select.mjs.map +1 -1
  39. package/fesm2022/skra-ui-popover.mjs +25 -9
  40. package/fesm2022/skra-ui-popover.mjs.map +1 -1
  41. package/fesm2022/skra-ui-progress.mjs.map +1 -1
  42. package/fesm2022/skra-ui-radio.mjs +2 -2
  43. package/fesm2022/skra-ui-radio.mjs.map +1 -1
  44. package/fesm2022/skra-ui-rating-display.mjs +2 -2
  45. package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
  46. package/fesm2022/skra-ui-select.mjs +92 -92
  47. package/fesm2022/skra-ui-select.mjs.map +1 -1
  48. package/fesm2022/skra-ui-skeleton.mjs +8 -8
  49. package/fesm2022/skra-ui-skeleton.mjs.map +1 -1
  50. package/fesm2022/skra-ui-star-rating.mjs +2 -2
  51. package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
  52. package/fesm2022/skra-ui-status-dot.mjs.map +1 -1
  53. package/fesm2022/skra-ui-switch.mjs +2 -2
  54. package/fesm2022/skra-ui-switch.mjs.map +1 -1
  55. package/fesm2022/skra-ui-tabs.mjs +2 -2
  56. package/fesm2022/skra-ui-tabs.mjs.map +1 -1
  57. package/fesm2022/skra-ui-textarea.mjs +2 -2
  58. package/fesm2022/skra-ui-textarea.mjs.map +1 -1
  59. package/fesm2022/skra-ui-toast.mjs +2 -2
  60. package/fesm2022/skra-ui-toast.mjs.map +1 -1
  61. package/fesm2022/skra-ui-tooltip.mjs +7 -2
  62. package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
  63. package/fesm2022/skra-ui-typography.mjs.map +1 -1
  64. package/package.json +3 -3
  65. package/types/skra-ui-core.d.ts.map +1 -1
  66. package/types/skra-ui-datepicker.d.ts +146 -46
  67. package/types/skra-ui-datepicker.d.ts.map +1 -1
  68. package/types/skra-ui-menu.d.ts +18 -6
  69. package/types/skra-ui-menu.d.ts.map +1 -1
  70. package/types/skra-ui-popover.d.ts +13 -4
  71. package/types/skra-ui-popover.d.ts.map +1 -1
  72. package/types/skra-ui-tooltip.d.ts.map +1 -1
@@ -57,7 +57,7 @@ class SkraInput {
57
57
  }
58
58
  }
59
59
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
60
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraInput, isStandalone: true, selector: "input[skraInput]", 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: '', 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 });
60
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraInput, isStandalone: true, selector: "input[skraInput]", 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: '', 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)}:host([type=date]),:host([type=month]),:host([type=week]),:host([type=time]),:host([type=datetime-local]){box-sizing:border-box;min-block-size:var(--skra-comp-field-temporal-min-block-size);padding-inline-end:var(--skra-comp-field-temporal-indicator-padding-inline-end)}:host([type=date])::-webkit-calendar-picker-indicator,:host([type=month])::-webkit-calendar-picker-indicator,:host([type=week])::-webkit-calendar-picker-indicator,:host([type=datetime-local])::-webkit-calendar-picker-indicator{background-image:var(--skra-comp-field-calendar-indicator-glyph)}:host([type=time])::-webkit-calendar-picker-indicator{background-image:var(--skra-comp-field-clock-indicator-glyph)}:host([type=date])::-webkit-calendar-picker-indicator,:host([type=month])::-webkit-calendar-picker-indicator,:host([type=week])::-webkit-calendar-picker-indicator,:host([type=time])::-webkit-calendar-picker-indicator,:host([type=datetime-local])::-webkit-calendar-picker-indicator{inline-size:var(--skra-comp-field-temporal-indicator-icon-size);block-size:var(--skra-comp-field-temporal-indicator-icon-size);background-repeat:no-repeat;background-position:center;background-size:contain;opacity:1;cursor:pointer}:host(:disabled)::-webkit-calendar-picker-indicator{cursor:not-allowed}:host::-webkit-datetime-edit{color:var(--skra-comp-field-foreground)}:host::-webkit-datetime-edit-fields-wrapper{padding-block:0}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
61
61
  }
62
62
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraInput, decorators: [{
63
63
  type: Component,
@@ -72,7 +72,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
72
72
  // state is forbidden). Readonly styling keys off `:read-only`/`[readonly]`.
73
73
  // The native props are driven imperatively below, NOT as host bindings —
74
74
  // see the constructor note on standalone attribute ownership.
75
- }, 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"] }]
75
+ }, 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)}:host([type=date]),:host([type=month]),:host([type=week]),:host([type=time]),:host([type=datetime-local]){box-sizing:border-box;min-block-size:var(--skra-comp-field-temporal-min-block-size);padding-inline-end:var(--skra-comp-field-temporal-indicator-padding-inline-end)}:host([type=date])::-webkit-calendar-picker-indicator,:host([type=month])::-webkit-calendar-picker-indicator,:host([type=week])::-webkit-calendar-picker-indicator,:host([type=datetime-local])::-webkit-calendar-picker-indicator{background-image:var(--skra-comp-field-calendar-indicator-glyph)}:host([type=time])::-webkit-calendar-picker-indicator{background-image:var(--skra-comp-field-clock-indicator-glyph)}:host([type=date])::-webkit-calendar-picker-indicator,:host([type=month])::-webkit-calendar-picker-indicator,:host([type=week])::-webkit-calendar-picker-indicator,:host([type=time])::-webkit-calendar-picker-indicator,:host([type=datetime-local])::-webkit-calendar-picker-indicator{inline-size:var(--skra-comp-field-temporal-indicator-icon-size);block-size:var(--skra-comp-field-temporal-indicator-icon-size);background-repeat:no-repeat;background-position:center;background-size:contain;opacity:1;cursor:pointer}:host(:disabled)::-webkit-calendar-picker-indicator{cursor:not-allowed}:host::-webkit-datetime-edit{color:var(--skra-comp-field-foreground)}:host::-webkit-datetime-edit-fields-wrapper{padding-block:0}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
76
76
  }], ctorParameters: () => [] });
77
77
 
78
78
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-input.mjs","sources":["../../../../libs/ui/input/src/lib/input/input.ts","../../../../libs/ui/input/src/skra-ui-input.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 * `input[skraInput]` — text-input atom. Per ADR 040 this is a\n * Component-on-a-native-host (not a directive): `<input>` is a void element, so\n * `template: ''` is correct — there is no consumer content to project. Angular\n * Emulated encapsulation scopes `input.scss` to the host, the same way\n * <skra-button> carries its own CSS. Replaces the ADR 038 global slice branch.\n *\n * DI wiring (ADR 013), host a11y bindings (ADR 021/027), and the agnostic\n * value posture (ADR 037 — no value channel, no @angular/forms) are unchanged\n * from the prior directive form.\n *\n * `SkraFieldContext` is injected `{ optional: true }` (ADR 013 §3.7) — the same\n * posture as `skraCheckbox` / `skraRadio` / `skraSwitch`. Inside `<skra-field>`\n * the atom takes the field's id + describedby + availability cascade; standalone\n * it renders the skin only and the consumer owns every attribute, including the\n * accessible name:\n *\n * <!-- inside Field — label association via the DI-generated id/for pair -->\n * <skra-field>\n * <label skraLabelFor>Email</label>\n * <input skraInput type=\"email\" />\n * </skra-field>\n *\n * <!-- standalone: native implicit label (wrapping) — no id/for needed -->\n * <label>Search <input skraInput type=\"search\" /></label>\n *\n * Standalone use does NOT relax the ADR 033 accessible-name contract; it moves\n * the name onto the consumer's own native markup. An input with no name is an\n * a11y defect wherever it appears — including inside a `<skra-field>` that\n * carries no `label[skraLabelFor]` — so the check belongs to the a11y gate, not\n * to this injection site (ADR 013 §3.7).\n */\n@Component({\n selector: 'input[skraInput]',\n standalone: true,\n // Void host — no <ng-content>. See ADR 040 §2.\n template: '',\n styleUrl: './input.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). <input>\n // supports native `readonly`/`disabled`, which AT already exposes; NO\n // `aria-readonly`/`aria-disabled` here (setting both native + ARIA for one\n // state is forbidden). Readonly styling keys off `:read-only`/`[readonly]`.\n // The native props are driven imperatively below, NOT as host bindings —\n // see the constructor note on standalone attribute ownership.\n },\n})\nexport class SkraInput {\n private readonly el = inject<ElementRef<HTMLInputElement>>(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 // (a host `[attr.disabled]=\"null\"` binding would strip a consumer-authored\n // `disabled` / `readonly` / `id`). Mirrors 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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,SAAS,CAAA;AACH,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;AACE,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;;;;;AAMhC,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;uGAvBW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAT,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,SAAS,mSAjBV,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,i/CAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,SAAS,EAAA,UAAA,EAAA,CAAA;kBArBrB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,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;;;;;;;AAOhE,qBAAA,EAAA,MAAA,EAAA,CAAA,i/CAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-input.mjs","sources":["../../../../libs/ui/input/src/lib/input/input.ts","../../../../libs/ui/input/src/skra-ui-input.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 * `input[skraInput]` — text-input atom. Per ADR 040 this is a\n * Component-on-a-native-host (not a directive): `<input>` is a void element, so\n * `template: ''` is correct — there is no consumer content to project. Angular\n * Emulated encapsulation scopes `input.scss` to the host, the same way\n * <skra-button> carries its own CSS. Replaces the ADR 038 global slice branch.\n *\n * DI wiring (ADR 013), host a11y bindings (ADR 021/027), and the agnostic\n * value posture (ADR 037 — no value channel, no @angular/forms) are unchanged\n * from the prior directive form.\n *\n * `SkraFieldContext` is injected `{ optional: true }` (ADR 013 §3.7) — the same\n * posture as `skraCheckbox` / `skraRadio` / `skraSwitch`. Inside `<skra-field>`\n * the atom takes the field's id + describedby + availability cascade; standalone\n * it renders the skin only and the consumer owns every attribute, including the\n * accessible name:\n *\n * <!-- inside Field — label association via the DI-generated id/for pair -->\n * <skra-field>\n * <label skraLabelFor>Email</label>\n * <input skraInput type=\"email\" />\n * </skra-field>\n *\n * <!-- standalone: native implicit label (wrapping) — no id/for needed -->\n * <label>Search <input skraInput type=\"search\" /></label>\n *\n * Standalone use does NOT relax the ADR 033 accessible-name contract; it moves\n * the name onto the consumer's own native markup. An input with no name is an\n * a11y defect wherever it appears — including inside a `<skra-field>` that\n * carries no `label[skraLabelFor]` — so the check belongs to the a11y gate, not\n * to this injection site (ADR 013 §3.7).\n */\n@Component({\n selector: 'input[skraInput]',\n standalone: true,\n // Void host — no <ng-content>. See ADR 040 §2.\n template: '',\n styleUrl: './input.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). <input>\n // supports native `readonly`/`disabled`, which AT already exposes; NO\n // `aria-readonly`/`aria-disabled` here (setting both native + ARIA for one\n // state is forbidden). Readonly styling keys off `:read-only`/`[readonly]`.\n // The native props are driven imperatively below, NOT as host bindings —\n // see the constructor note on standalone attribute ownership.\n },\n})\nexport class SkraInput {\n private readonly el = inject<ElementRef<HTMLInputElement>>(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 // (a host `[attr.disabled]=\"null\"` binding would strip a consumer-authored\n // `disabled` / `readonly` / `id`). Mirrors 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","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,SAAS,CAAA;AACH,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;AACE,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;;;;;AAMhC,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;uGAvBW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAT,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,SAAS,mSAjBV,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,s4FAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,SAAS,EAAA,UAAA,EAAA,CAAA;kBArBrB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,kBAAkB,EAAA,UAAA,EAChB,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,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;;;;;;;AAOhE,qBAAA,EAAA,MAAA,EAAA,CAAA,s4FAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-kbd.mjs","sources":["../../../../libs/ui/kbd/src/lib/kbd/kbd.ts","../../../../libs/ui/kbd/src/skra-ui-kbd.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\n\r\n/**\r\n * `kbd[skraKbd]` — keyboard-key display atom (first resident of `libs/ui/content`, the\r\n * text-level inline-semantics family). Renders a single key / key-name as a styled key-cap for\r\n * docs, shortcut hints and help text (\"press `Esc` to close\"). See\r\n * `adr/specs/component-kbd-spec.md`.\r\n *\r\n * **Component-on-the-native-host (ADR 040), NOT `<skra-kbd>`:** native `<kbd>` already carries\r\n * the correct HTML semantic (\"user keyboard input\"), so we decorate it (ADR 012). `<kbd>` is\r\n * content-bearing, so the template MUST be `<ng-content>` — `template: ''` would discard the key\r\n * text (ADR 040 §2; the `label[skraLabelFor]` precedent).\r\n *\r\n * **Zero inputs by design.** A key display is purely presentational:\r\n * - sizing is em-relative (it harmonises with the surrounding text), so there is no `size` input\r\n * — an explicit size enum would be a look-input (skin-philosophy) and low-demand (90%-rule);\r\n * - no coherent semantic exists for a `type`, and a `type` enum switching appearance is the SRP\r\n * smell the Decision Doctrine warns against;\r\n * - the monospace family is skin-owned (`--skra-comp-kbd-font-family` → `sys.font-family.code`);\r\n * - key-combos (\"Ctrl+C\") are consumer composition of multiple `<kbd skraKbd>` (agnostic\r\n * doctrine), not a `combo` input.\r\n *\r\n * So there is no input, no output, no `data-skra-*` state (non-interactive — State Surface\r\n * all-N/A), and no `ariaLabel` (the visible text IS the accessible content, ADR 033). The host is\r\n * deliberately **not** `aria-hidden`: the key name is meaningful content AT must announce.\r\n */\r\n@Component({\r\n selector: 'kbd[skraKbd]',\r\n standalone: true,\r\n // Content-bearing host — see ADR 040 §2 (label precedent).\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './kbd.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n class: 'skra-kbd',\r\n },\r\n})\r\nexport class SkraKbd {}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAMA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MAaU,OAAO,CAAA;uGAAP,OAAO,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAP,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,OAAO,8GARR,2BAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,oxBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAQ1B,OAAO,EAAA,UAAA,EAAA,CAAA;kBAZnB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,EAAA,UAAA,EACZ,IAAI,EAAA,QAAA,EAEN,2BAA2B,EAAA,eAAA,EAEpB,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;AACJ,wBAAA,KAAK,EAAE,UAAU;AAClB,qBAAA,EAAA,MAAA,EAAA,CAAA,oxBAAA,CAAA,EAAA;;;ACxCH;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-kbd.mjs","sources":["../../../../libs/ui/kbd/src/lib/kbd/kbd.ts","../../../../libs/ui/kbd/src/skra-ui-kbd.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n} from '@angular/core';\n\n/**\n * `kbd[skraKbd]` — keyboard-key display atom (first resident of `libs/ui/content`, the\n * text-level inline-semantics family). Renders a single key / key-name as a styled key-cap for\n * docs, shortcut hints and help text (\"press `Esc` to close\"). See\n * `adr/specs/component-kbd-spec.md`.\n *\n * **Component-on-the-native-host (ADR 040), NOT `<skra-kbd>`:** native `<kbd>` already carries\n * the correct HTML semantic (\"user keyboard input\"), so we decorate it (ADR 012). `<kbd>` is\n * content-bearing, so the template MUST be `<ng-content>` — `template: ''` would discard the key\n * text (ADR 040 §2; the `label[skraLabelFor]` precedent).\n *\n * **Zero inputs by design.** A key display is purely presentational:\n * - sizing is em-relative (it harmonises with the surrounding text), so there is no `size` input\n * — an explicit size enum would be a look-input (skin-philosophy) and low-demand (90%-rule);\n * - no coherent semantic exists for a `type`, and a `type` enum switching appearance is the SRP\n * smell the Decision Doctrine warns against;\n * - the monospace family is skin-owned (`--skra-comp-kbd-font-family` → `sys.font-family.code`);\n * - key-combos (\"Ctrl+C\") are consumer composition of multiple `<kbd skraKbd>` (agnostic\n * doctrine), not a `combo` input.\n *\n * So there is no input, no output, no `data-skra-*` state (non-interactive — State Surface\n * all-N/A), and no `ariaLabel` (the visible text IS the accessible content, ADR 033). The host is\n * deliberately **not** `aria-hidden`: the key name is meaningful content AT must announce.\n */\n@Component({\n selector: 'kbd[skraKbd]',\n standalone: true,\n // Content-bearing host — see ADR 040 §2 (label precedent).\n template: '<ng-content></ng-content>',\n styleUrl: './kbd.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n class: 'skra-kbd',\n },\n})\nexport class SkraKbd {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAMA;;;;;;;;;;;;;;;;;;;;;;;AAuBG;MAaU,OAAO,CAAA;uGAAP,OAAO,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAP,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,OAAO,8GARR,2BAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,oxBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAQ1B,OAAO,EAAA,UAAA,EAAA,CAAA;kBAZnB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,cAAc,EAAA,UAAA,EACZ,IAAI,EAAA,QAAA,EAEN,2BAA2B,EAAA,eAAA,EAEpB,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;AACJ,wBAAA,KAAK,EAAE,UAAU;AAClB,qBAAA,EAAA,MAAA,EAAA,CAAA,oxBAAA,CAAA,EAAA;;;ACxCH;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-layout.mjs","sources":["../../../../libs/ui/layout/src/lib/box/box.ts","../../../../libs/ui/layout/src/lib/stack/stack.ts","../../../../libs/ui/layout/src/lib/grid/grid.ts","../../../../libs/ui/layout/src/lib/surface/surface.ts","../../../../libs/ui/layout/src/skra-ui-layout.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type BoxPadding = 'none' | 'sm' | 'md' | 'lg';\r\nexport type BoxDisplay = 'block' | 'inline-block' | 'flex';\r\n\r\n/**\r\n * SkraBox — semantically-neutral spacing/padding primitive (ADR 041).\r\n *\r\n * Component-on-native-host: layers onto a generic flow/sectioning container via\r\n * the bounded host allowlist below — NEVER a `<skra-box>` custom element\r\n * (ADR 012 §3.1 / ADR 041). Box does NOT arrange children, so list hosts\r\n * (`ul`/`ol`/`menu`) are intentionally excluded from its allowlist.\r\n *\r\n * Box is a pure spacing primitive: it MUST NOT establish a container-query\r\n * context (`container-type`/`container-name`) — that is an app-level concern\r\n * (ADR 016 §3.3, amended by ADR 041).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraBox], section[skraBox], article[skraBox], main[skraBox], nav[skraBox], aside[skraBox], header[skraBox], footer[skraBox], form[skraBox], figure[skraBox]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './box.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021) — NO inline styles! The layout reset\r\n // (margin/box-sizing) + figure UA-margin normalization live in box.scss\r\n // `:host` (ADR 022 / ADR 041 Host Normalization Contract); host-metadata\r\n // bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-padding]': 'padding()',\r\n '[attr.data-skra-display]': 'display()',\r\n },\r\n})\r\nexport class SkraBox {\r\n readonly padding = input<BoxPadding>('none');\r\n readonly display = input<BoxDisplay>('block');\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type StackDirection = 'row' | 'column';\r\nexport type StackGap = 'none' | 'sm' | 'md' | 'lg';\r\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\r\nexport type StackJustify = 'start' | 'center' | 'end' | 'between' | 'around';\r\n\r\n/**\r\n * SkraStack — flex layout primitive that arranges its children (ADR 041).\r\n *\r\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\r\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\r\n * is normalized in stack.scss per the Host Normalization Contract. List markers\r\n * are restorable without `!important` via a direct `li {}` rule (a direct\r\n * declaration beats the inherited `list-style: none`).\r\n *\r\n * Stack consumes `@container`; it MUST NOT establish a container-query context\r\n * (ADR 016 §3.3, amended by ADR 041).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraStack], section[skraStack], article[skraStack], main[skraStack], nav[skraStack], aside[skraStack], header[skraStack], footer[skraStack], form[skraStack], figure[skraStack], ul[skraStack], ol[skraStack], menu[skraStack]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './stack.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The\r\n // layout reset (margin/box-sizing) + list/UA normalization live in\r\n // stack.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\r\n // host-metadata bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-direction]': 'direction()',\r\n '[attr.data-skra-gap]': 'gap()',\r\n '[attr.data-skra-align]': 'align()',\r\n '[attr.data-skra-justify]': 'justify()',\r\n '[attr.data-skra-wrap]': 'wrap() ? \"\" : null',\r\n },\r\n})\r\nexport class SkraStack {\r\n readonly direction = input<StackDirection>('column');\r\n readonly gap = input<StackGap>('md');\r\n readonly align = input<StackAlign>('stretch');\r\n readonly justify = input<StackJustify>('start');\r\n readonly wrap = input(false, { transform: booleanAttribute });\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type GridColumns =\r\n | '1'\r\n | '2'\r\n | '3'\r\n | '4'\r\n | '5'\r\n | '6'\r\n | 'auto-fit'\r\n | 'auto-fill';\r\nexport type GridMin = 'sm' | 'md' | 'lg';\r\nexport type GridGap = 'none' | 'sm' | 'md' | 'lg';\r\nexport type GridFlow = 'row' | 'column' | 'dense';\r\nexport type GridAlign = 'start' | 'center' | 'end' | 'stretch';\r\n\r\n/**\r\n * SkraGrid — 2D layout primitive that arranges its children in a CSS Grid\r\n * (ADR 041, scope O-3). The bucket-only companion to Stack (1D) and Box (spacing).\r\n *\r\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\r\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\r\n * is normalized in grid.scss per the Host Normalization Contract.\r\n *\r\n * Bucket-only by design: every axis is an enumerated input reflected as a\r\n * `data-skra-*` attribute → token. Arbitrary track lists, `grid-template-areas`,\r\n * named lines and per-item placement are OUT of scope (bespoke = native CSS) —\r\n * exposing them would force an `[style.*]` host binding (ADR 021 violation).\r\n *\r\n * Responsiveness: `columns=\"auto-fit\"` (default) + `min` produce an intrinsically\r\n * responsive card grid via `repeat(auto-fit, minmax(var(--min), 1fr))` — column\r\n * count tracks available width with NO media/container queries. Grid consumes\r\n * `@container`; it MUST NOT establish a container-query context (ADR 041 §3.3).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraGrid], section[skraGrid], article[skraGrid], main[skraGrid], nav[skraGrid], aside[skraGrid], header[skraGrid], footer[skraGrid], form[skraGrid], figure[skraGrid], ul[skraGrid], ol[skraGrid], menu[skraGrid]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './grid.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The layout\r\n // reset (margin/box-sizing/display:grid) + list/UA normalization live in\r\n // grid.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\r\n // host-metadata bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-columns]': 'columns()',\r\n '[attr.data-skra-min]': 'min()',\r\n '[attr.data-skra-gap]': 'gap()',\r\n '[attr.data-skra-flow]': 'flow()',\r\n '[attr.data-skra-align]': 'align()',\r\n '[attr.data-skra-justify-items]': 'justifyItems()',\r\n },\r\n})\r\nexport class SkraGrid {\r\n readonly columns = input<GridColumns>('auto-fit');\r\n readonly min = input<GridMin>('md');\r\n readonly gap = input<GridGap>('md');\r\n readonly flow = input<GridFlow>('row');\r\n readonly align = input<GridAlign>('stretch');\r\n readonly justifyItems = input<GridAlign>('stretch');\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type SurfacePadding = 'none' | 'sm' | 'md' | 'lg';\r\n\r\n/**\r\n * SkraSurface — the painted container primitive (ADR 0053), Box's painting sibling.\r\n *\r\n * Component-on-native-host: layers onto a generic flow/sectioning container via the\r\n * bounded host allowlist below — NEVER a `<skra-surface>` custom element, and never\r\n * an interactive host (ADR 0055 R3.1: `a[skraSurface]` / `button[skraSurface]` are\r\n * unsupported). \"Card\", \"Panel\" and \"Tile\" are consumer compositions of Surface +\r\n * `[skraStack]`/`[skraBox]` + a heading — not Skra components (ADR 0053 rule 1).\r\n *\r\n * **State-reading doctrine (ADR 0055).** Surface is a READER of state, never an\r\n * OWNER of state. It exposes no `interactive`/`hoverable`/`selected`/`elevation`\r\n * input and emits no `role`/`tabindex`/`aria-*`. Focus and selection are READ from\r\n * the markup the consumer authored (see surface.scss) — which is why an\r\n * informational card gets no interactive paint with zero API, and why a selected\r\n * card can never disagree with what assistive technology announces.\r\n *\r\n * Zero baked semantics: sectioning role and accessible name are 100% consumer-owned\r\n * (ADR 0053 rule 6). No `container-type` in v1 (ADR 0055 R7.1).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraSurface], section[skraSurface], article[skraSurface], main[skraSurface], nav[skraSurface], aside[skraSurface], header[skraSurface], footer[skraSurface], figure[skraSurface]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './surface.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021) — NO inline styles. This is the ONLY\r\n // host attribute Surface emits (ADR 0055 R2): no role, no tabindex, no aria-*.\r\n '[attr.data-skra-padding]': 'padding()',\r\n },\r\n})\r\nexport class SkraSurface {\r\n /**\r\n * Semantic padding preset, reusing Box's enum for cross-atom consistency\r\n * (ADR 0053 rule 4). Defaults to `md` rather than Box's `none` — Box is\r\n * spacing-neutral by construction, a painted container is not (ADR 0055 R1).\r\n */\r\n readonly padding = input<SurfacePadding>('md');\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-layout.mjs","sources":["../../../../libs/ui/layout/src/lib/box/box.ts","../../../../libs/ui/layout/src/lib/stack/stack.ts","../../../../libs/ui/layout/src/lib/grid/grid.ts","../../../../libs/ui/layout/src/lib/surface/surface.ts","../../../../libs/ui/layout/src/skra-ui-layout.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\nexport type BoxPadding = 'none' | 'sm' | 'md' | 'lg';\nexport type BoxDisplay = 'block' | 'inline-block' | 'flex';\n\n/**\n * SkraBox — semantically-neutral spacing/padding primitive (ADR 041).\n *\n * Component-on-native-host: layers onto a generic flow/sectioning container via\n * the bounded host allowlist below — NEVER a `<skra-box>` custom element\n * (ADR 012 §3.1 / ADR 041). Box does NOT arrange children, so list hosts\n * (`ul`/`ol`/`menu`) are intentionally excluded from its allowlist.\n *\n * Box is a pure spacing primitive: it MUST NOT establish a container-query\n * context (`container-type`/`container-name`) — that is an app-level concern\n * (ADR 016 §3.3, amended by ADR 041).\n */\n@Component({\n selector:\n 'div[skraBox], section[skraBox], article[skraBox], main[skraBox], nav[skraBox], aside[skraBox], header[skraBox], footer[skraBox], form[skraBox], figure[skraBox]',\n standalone: true,\n template: '<ng-content></ng-content>',\n styleUrl: './box.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // CSP-Safe State Reflection (ADR 021) — NO inline styles! The layout reset\n // (margin/box-sizing) + figure UA-margin normalization live in box.scss\n // `:host` (ADR 022 / ADR 041 Host Normalization Contract); host-metadata\n // bare keys would render as junk attributes, not styles.\n '[attr.data-skra-padding]': 'padding()',\n '[attr.data-skra-display]': 'display()',\n },\n})\nexport class SkraBox {\n readonly padding = input<BoxPadding>('none');\n readonly display = input<BoxDisplay>('block');\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n booleanAttribute,\n input,\n} from '@angular/core';\n\nexport type StackDirection = 'row' | 'column';\nexport type StackGap = 'none' | 'sm' | 'md' | 'lg';\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\nexport type StackJustify = 'start' | 'center' | 'end' | 'between' | 'around';\n\n/**\n * SkraStack — flex layout primitive that arranges its children (ADR 041).\n *\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\n * is normalized in stack.scss per the Host Normalization Contract. List markers\n * are restorable without `!important` via a direct `li {}` rule (a direct\n * declaration beats the inherited `list-style: none`).\n *\n * Stack consumes `@container`; it MUST NOT establish a container-query context\n * (ADR 016 §3.3, amended by ADR 041).\n */\n@Component({\n selector:\n 'div[skraStack], section[skraStack], article[skraStack], main[skraStack], nav[skraStack], aside[skraStack], header[skraStack], footer[skraStack], form[skraStack], figure[skraStack], ul[skraStack], ol[skraStack], menu[skraStack]',\n standalone: true,\n template: '<ng-content></ng-content>',\n styleUrl: './stack.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The\n // layout reset (margin/box-sizing) + list/UA normalization live in\n // stack.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\n // host-metadata bare keys would render as junk attributes, not styles.\n '[attr.data-skra-direction]': 'direction()',\n '[attr.data-skra-gap]': 'gap()',\n '[attr.data-skra-align]': 'align()',\n '[attr.data-skra-justify]': 'justify()',\n '[attr.data-skra-wrap]': 'wrap() ? \"\" : null',\n },\n})\nexport class SkraStack {\n readonly direction = input<StackDirection>('column');\n readonly gap = input<StackGap>('md');\n readonly align = input<StackAlign>('stretch');\n readonly justify = input<StackJustify>('start');\n readonly wrap = input(false, { transform: booleanAttribute });\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\nexport type GridColumns =\n | '1'\n | '2'\n | '3'\n | '4'\n | '5'\n | '6'\n | 'auto-fit'\n | 'auto-fill';\nexport type GridMin = 'sm' | 'md' | 'lg';\nexport type GridGap = 'none' | 'sm' | 'md' | 'lg';\nexport type GridFlow = 'row' | 'column' | 'dense';\nexport type GridAlign = 'start' | 'center' | 'end' | 'stretch';\n\n/**\n * SkraGrid — 2D layout primitive that arranges its children in a CSS Grid\n * (ADR 041, scope O-3). The bucket-only companion to Stack (1D) and Box (spacing).\n *\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\n * is normalized in grid.scss per the Host Normalization Contract.\n *\n * Bucket-only by design: every axis is an enumerated input reflected as a\n * `data-skra-*` attribute → token. Arbitrary track lists, `grid-template-areas`,\n * named lines and per-item placement are OUT of scope (bespoke = native CSS) —\n * exposing them would force an `[style.*]` host binding (ADR 021 violation).\n *\n * Responsiveness: `columns=\"auto-fit\"` (default) + `min` produce an intrinsically\n * responsive card grid via `repeat(auto-fit, minmax(var(--min), 1fr))` — column\n * count tracks available width with NO media/container queries. Grid consumes\n * `@container`; it MUST NOT establish a container-query context (ADR 041 §3.3).\n */\n@Component({\n selector:\n 'div[skraGrid], section[skraGrid], article[skraGrid], main[skraGrid], nav[skraGrid], aside[skraGrid], header[skraGrid], footer[skraGrid], form[skraGrid], figure[skraGrid], ul[skraGrid], ol[skraGrid], menu[skraGrid]',\n standalone: true,\n template: '<ng-content></ng-content>',\n styleUrl: './grid.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The layout\n // reset (margin/box-sizing/display:grid) + list/UA normalization live in\n // grid.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\n // host-metadata bare keys would render as junk attributes, not styles.\n '[attr.data-skra-columns]': 'columns()',\n '[attr.data-skra-min]': 'min()',\n '[attr.data-skra-gap]': 'gap()',\n '[attr.data-skra-flow]': 'flow()',\n '[attr.data-skra-align]': 'align()',\n '[attr.data-skra-justify-items]': 'justifyItems()',\n },\n})\nexport class SkraGrid {\n readonly columns = input<GridColumns>('auto-fit');\n readonly min = input<GridMin>('md');\n readonly gap = input<GridGap>('md');\n readonly flow = input<GridFlow>('row');\n readonly align = input<GridAlign>('stretch');\n readonly justifyItems = input<GridAlign>('stretch');\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n input,\n} from '@angular/core';\n\nexport type SurfacePadding = 'none' | 'sm' | 'md' | 'lg';\n\n/**\n * SkraSurface — the painted container primitive (ADR 0053), Box's painting sibling.\n *\n * Component-on-native-host: layers onto a generic flow/sectioning container via the\n * bounded host allowlist below — NEVER a `<skra-surface>` custom element, and never\n * an interactive host (ADR 0055 R3.1: `a[skraSurface]` / `button[skraSurface]` are\n * unsupported). \"Card\", \"Panel\" and \"Tile\" are consumer compositions of Surface +\n * `[skraStack]`/`[skraBox]` + a heading — not Skra components (ADR 0053 rule 1).\n *\n * **State-reading doctrine (ADR 0055).** Surface is a READER of state, never an\n * OWNER of state. It exposes no `interactive`/`hoverable`/`selected`/`elevation`\n * input and emits no `role`/`tabindex`/`aria-*`. Focus and selection are READ from\n * the markup the consumer authored (see surface.scss) — which is why an\n * informational card gets no interactive paint with zero API, and why a selected\n * card can never disagree with what assistive technology announces.\n *\n * Zero baked semantics: sectioning role and accessible name are 100% consumer-owned\n * (ADR 0053 rule 6). No `container-type` in v1 (ADR 0055 R7.1).\n */\n@Component({\n selector:\n 'div[skraSurface], section[skraSurface], article[skraSurface], main[skraSurface], nav[skraSurface], aside[skraSurface], header[skraSurface], footer[skraSurface], figure[skraSurface]',\n standalone: true,\n template: '<ng-content></ng-content>',\n styleUrl: './surface.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // CSP-Safe State Reflection (ADR 021) — NO inline styles. This is the ONLY\n // host attribute Surface emits (ADR 0055 R2): no role, no tabindex, no aria-*.\n '[attr.data-skra-padding]': 'padding()',\n },\n})\nexport class SkraSurface {\n /**\n * Semantic padding preset, reusing Box's enum for cross-atom consistency\n * (ADR 0053 rule 4). Defaults to `md` rather than Box's `none` — Box is\n * spacing-neutral by construction, a painted container is not (ADR 0055 R1).\n */\n readonly padding = input<SurfacePadding>('md');\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -14,11 +14,11 @@ import { ViewEncapsulation, ChangeDetectionStrategy, Component } from '@angular/
14
14
  */
15
15
  class SkraLink {
16
16
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraLink, deps: [], target: i0.ɵɵFactoryTarget.Component });
17
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraLink, isStandalone: true, selector: "a[skraLink]", ngImport: i0, template: "<ng-content></ng-content>\n", styles: [":host{margin:0;color:var(--skra-comp-link-foreground);text-decoration-line:var(--skra-comp-link-text-decoration-line);text-decoration-thickness:var(--skra-comp-link-text-decoration-thickness);text-underline-offset:var(--skra-comp-link-text-underline-offset);transition:color var(--skra-comp-link-motion-duration) var(--skra-comp-link-motion-easing)}:host:visited{color:var(--skra-comp-link-foreground-visited)}:host:hover{color:var(--skra-comp-link-foreground-hover)}:host:active{color:var(--skra-comp-link-foreground-active)}:host:focus-visible{outline-style:solid;outline-color:var(--skra-comp-link-focus-ring-color);outline-width:var(--skra-comp-link-focus-ring-width);outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
17
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraLink, isStandalone: true, selector: "a[skraLink]", ngImport: i0, template: "<ng-content></ng-content>\n", styles: [":host{margin:0;color:var(--skra-comp-link-foreground);text-decoration-line:var(--skra-comp-link-text-decoration-line);text-decoration-thickness:var(--skra-comp-link-text-decoration-thickness);text-underline-offset:var(--skra-comp-link-text-underline-offset);transition:color var(--skra-comp-link-motion-duration) var(--skra-comp-link-motion-easing)}:host:visited{color:var(--skra-comp-link-foreground-visited)}@media(hover:hover)and (pointer:fine){:host:hover{color:var(--skra-comp-link-foreground-hover)}}:host:active{color:var(--skra-comp-link-foreground-active)}:host:focus-visible{outline-style:solid;outline-color:var(--skra-comp-link-focus-ring-color);outline-width:var(--skra-comp-link-focus-ring-width);outline-offset:2px}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
18
18
  }
19
19
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraLink, decorators: [{
20
20
  type: Component,
21
- args: [{ selector: 'a[skraLink]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, template: "<ng-content></ng-content>\n", styles: [":host{margin:0;color:var(--skra-comp-link-foreground);text-decoration-line:var(--skra-comp-link-text-decoration-line);text-decoration-thickness:var(--skra-comp-link-text-decoration-thickness);text-underline-offset:var(--skra-comp-link-text-underline-offset);transition:color var(--skra-comp-link-motion-duration) var(--skra-comp-link-motion-easing)}:host:visited{color:var(--skra-comp-link-foreground-visited)}:host:hover{color:var(--skra-comp-link-foreground-hover)}:host:active{color:var(--skra-comp-link-foreground-active)}:host:focus-visible{outline-style:solid;outline-color:var(--skra-comp-link-focus-ring-color);outline-width:var(--skra-comp-link-focus-ring-width);outline-offset:2px}\n"] }]
21
+ args: [{ selector: 'a[skraLink]', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, template: "<ng-content></ng-content>\n", styles: [":host{margin:0;color:var(--skra-comp-link-foreground);text-decoration-line:var(--skra-comp-link-text-decoration-line);text-decoration-thickness:var(--skra-comp-link-text-decoration-thickness);text-underline-offset:var(--skra-comp-link-text-underline-offset);transition:color var(--skra-comp-link-motion-duration) var(--skra-comp-link-motion-easing)}:host:visited{color:var(--skra-comp-link-foreground-visited)}@media(hover:hover)and (pointer:fine){:host:hover{color:var(--skra-comp-link-foreground-hover)}}:host:active{color:var(--skra-comp-link-foreground-active)}:host:focus-visible{outline-style:solid;outline-color:var(--skra-comp-link-focus-ring-color);outline-width:var(--skra-comp-link-focus-ring-width);outline-offset:2px}\n"] }]
22
22
  }] });
23
23
 
24
24
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-link.mjs","sources":["../../../../libs/ui/link/src/lib/link/link.ts","../../../../libs/ui/link/src/lib/link/link.html","../../../../libs/ui/link/src/skra-ui-link.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\n\r\n/**\r\n * SkraLink — text-style anchor primitive (ADR 032 §3.6).\r\n *\r\n * Selector: `a[skraLink]` — `<a>` is the sole host.\r\n *\r\n * Per ADR 032 §3.6.3 there is no `disabled` input and no `data-skra-*`\r\n * Availability reflection: a link the user cannot or should not follow should\r\n * not be a link in the first place. Severity is deferred beyond MVP (§3.6.4).\r\n * Accessible Name follows ADR 033 Path 1 — visible text is the accessible name;\r\n * the component exposes no `ariaLabel` input.\r\n */\r\n@Component({\r\n selector: 'a[skraLink]',\r\n standalone: true,\r\n templateUrl: './link.html',\r\n styleUrl: './link.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n})\r\nexport class SkraLink {}\r\n","<ng-content></ng-content>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAMA;;;;;;;;;;AAUG;MASU,QAAQ,CAAA;uGAAR,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAR,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAQ,uECzBrB,6BACA,EAAA,MAAA,EAAA,CAAA,urBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDwBa,QAAQ,EAAA,UAAA,EAAA,CAAA;kBARpB,SAAS;+BACE,aAAa,EAAA,UAAA,EACX,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,QAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,CAAA,urBAAA,CAAA,EAAA;;;AEvB3C;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-link.mjs","sources":["../../../../libs/ui/link/src/lib/link/link.ts","../../../../libs/ui/link/src/lib/link/link.html","../../../../libs/ui/link/src/skra-ui-link.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n} from '@angular/core';\n\n/**\n * SkraLink — text-style anchor primitive (ADR 032 §3.6).\n *\n * Selector: `a[skraLink]` — `<a>` is the sole host.\n *\n * Per ADR 032 §3.6.3 there is no `disabled` input and no `data-skra-*`\n * Availability reflection: a link the user cannot or should not follow should\n * not be a link in the first place. Severity is deferred beyond MVP (§3.6.4).\n * Accessible Name follows ADR 033 Path 1 — visible text is the accessible name;\n * the component exposes no `ariaLabel` input.\n */\n@Component({\n selector: 'a[skraLink]',\n standalone: true,\n templateUrl: './link.html',\n styleUrl: './link.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n})\nexport class SkraLink {}\n","<ng-content></ng-content>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAMA;;;;;;;;;;AAUG;MASU,QAAQ,CAAA;uGAAR,QAAQ,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAR,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,QAAQ,uECzBrB,6BACA,EAAA,MAAA,EAAA,CAAA,8tBAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FDwBa,QAAQ,EAAA,UAAA,EAAA,CAAA;kBARpB,SAAS;+BACE,aAAa,EAAA,UAAA,EACX,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,QAAA,EAAA,6BAAA,EAAA,MAAA,EAAA,CAAA,8tBAAA,CAAA,EAAA;;;AEvB3C;;AAEG;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-loading-indicator.mjs","sources":["../../../../libs/ui/loading-indicator/src/lib/loading-indicator.directive.ts","../../../../libs/ui/loading-indicator/src/skra-ui-loading-indicator.ts"],"sourcesContent":["import { Directive } from '@angular/core';\r\n\r\n@Directive({\r\n selector: '[skraLoadingIndicator]',\r\n standalone: true,\r\n host: {\r\n 'aria-hidden': 'true',\r\n },\r\n})\r\nexport class SkraLoadingIndicator {}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MASa,oBAAoB,CAAA;uGAApB,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAPhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,wBAAwB;AAClC,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE;AACJ,wBAAA,aAAa,EAAE,MAAM;AACtB,qBAAA;AACF,iBAAA;;;ACRD;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-loading-indicator.mjs","sources":["../../../../libs/ui/loading-indicator/src/lib/loading-indicator.directive.ts","../../../../libs/ui/loading-indicator/src/skra-ui-loading-indicator.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n@Directive({\n selector: '[skraLoadingIndicator]',\n standalone: true,\n host: {\n 'aria-hidden': 'true',\n },\n})\nexport class SkraLoadingIndicator {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;MASa,oBAAoB,CAAA;uGAApB,oBAAoB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAApB,oBAAoB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,wBAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,aAAA,EAAA,MAAA,EAAA,EAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAApB,oBAAoB,EAAA,UAAA,EAAA,CAAA;kBAPhC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,wBAAwB;AAClC,oBAAA,UAAU,EAAE,IAAI;AAChB,oBAAA,IAAI,EAAE;AACJ,wBAAA,aAAa,EAAE,MAAM;AACtB,qBAAA;AACF,iBAAA;;;ACRD;;AAEG;;;;"}
@@ -6,7 +6,10 @@ import { FocusKeyManager } from '@angular/cdk/a11y';
6
6
  /**
7
7
  * SkraMenuKeyboard — the WAI-ARIA APG Menu keyboard model, confined to ONE file.
8
8
  *
9
- * This is the **only** module in Forge that imports `@angular/cdk`. It wraps CDK `FocusKeyManager`
9
+ * This is the only module in `@skra/ui/menu` that imports `@angular/cdk`. ADR 0044 §7 was later
10
+ * generalized library-wide to "one swappable `*-keyboard.ts` per APG pattern", so there are now
11
+ * three such files — this one, `core/select/listbox-keyboard.ts` (`ActiveDescendantKeyManager`) and
12
+ * `tabs/tabs-keyboard.ts` — enforced by `tools/cdk-confinement-validator.mjs`. It wraps CDK `FocusKeyManager`
10
13
  * (roving REAL focus — the APG-canonical menu model, NOT `aria-activedescendant`) so the engine is an
11
14
  * implementation detail: swapping it (e.g. to a hand-rolled controller) is a one-file change with zero
12
15
  * impact on `SkraMenu` / `SkraMenuItem` — exactly as `SkraPositioner` wraps `@floating-ui/dom`
@@ -107,8 +110,11 @@ class SkraMenuItem {
107
110
  }
108
111
  onActivate(event) {
109
112
  if (this.isDisabled()) {
110
- // Soft-disabled: block the native default AND the consumer's own (click) on this same host
111
- // (the host listener runs first — Material's MatMenuItem precedent).
113
+ // Soft-disabled: block the native default. This is a SECOND line of defence only — it cannot
114
+ // stop the consumer's own (click) on this same host, because a component host listener
115
+ // registers AFTER the parent template's binding, so this bubble-phase handler runs too late.
116
+ // The capture-phase guard on the panel (`SkraMenu`) is what actually blocks activation, for
117
+ // both pointer and keyboard (Enter/Space produce a UA-synthesized click). Do not delete it.
112
118
  event.preventDefault();
113
119
  event.stopImmediatePropagation();
114
120
  return;
@@ -117,7 +123,7 @@ class SkraMenuItem {
117
123
  this.menu?.requestClose();
118
124
  }
119
125
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component });
120
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraMenuItem, isStandalone: true, selector: "button[skraMenuItem]", host: { attributes: { "role": "menuitem", "type": "button", "tabindex": "-1" }, listeners: { "click": "onActivate($event)" } }, exportAs: ["skraMenuItem"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;gap:var(--skra-comp-menu-item-gap);inline-size:100%;min-block-size:var(--skra-comp-menu-item-min-block-size);margin:0;box-sizing:border-box;padding-block:var(--skra-comp-menu-item-padding-block);padding-inline:var(--skra-comp-menu-item-padding-inline);appearance:none;background:transparent;border:0;color:var(--skra-comp-menu-item-foreground);text-align:start;cursor:pointer;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);transition:background-color var(--skra-comp-menu-motion-duration) var(--skra-comp-menu-motion-easing)}:host(:hover:not([aria-disabled=true])),:host(:focus-visible:not([aria-disabled=true])){background-color:var(--skra-comp-menu-item-background-hover)}:host(:focus-visible){outline:var(--skra-comp-menu-focus-ring-width) solid var(--skra-comp-menu-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-menu-focus-ring-width))}:host([aria-disabled=true]){color:var(--skra-comp-menu-item-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
126
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraMenuItem, isStandalone: true, selector: "button[skraMenuItem]", host: { attributes: { "role": "menuitem", "type": "button", "tabindex": "-1" }, listeners: { "click": "onActivate($event)" } }, exportAs: ["skraMenuItem"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;gap:var(--skra-comp-menu-item-gap);inline-size:100%;min-block-size:var(--skra-comp-menu-item-min-block-size);margin:0;box-sizing:border-box;padding-block:var(--skra-comp-menu-item-padding-block);padding-inline:var(--skra-comp-menu-item-padding-inline);appearance:none;background:transparent;border:0;color:var(--skra-comp-menu-item-foreground);text-align:start;cursor:pointer;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);transition:background-color var(--skra-comp-menu-motion-duration) var(--skra-comp-menu-motion-easing)}@media(hover:hover)and (pointer:fine){:host(:hover:not([aria-disabled=true])){background-color:var(--skra-comp-menu-item-background-hover)}}:host(:focus-visible:not([aria-disabled=true])){background-color:var(--skra-comp-menu-item-background-hover)}:host(:focus-visible){outline:var(--skra-comp-menu-focus-ring-width) solid var(--skra-comp-menu-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-menu-focus-ring-width))}:host([aria-disabled=true]){color:var(--skra-comp-menu-item-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
121
127
  }
122
128
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraMenuItem, decorators: [{
123
129
  type: Component,
@@ -126,7 +132,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
126
132
  type: 'button', // never an implicit submit if the menu sits inside a <form>
127
133
  tabindex: '-1', // roving — focus is moved programmatically by SkraMenuKeyboard
128
134
  '(click)': 'onActivate($event)',
129
- }, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;gap:var(--skra-comp-menu-item-gap);inline-size:100%;min-block-size:var(--skra-comp-menu-item-min-block-size);margin:0;box-sizing:border-box;padding-block:var(--skra-comp-menu-item-padding-block);padding-inline:var(--skra-comp-menu-item-padding-inline);appearance:none;background:transparent;border:0;color:var(--skra-comp-menu-item-foreground);text-align:start;cursor:pointer;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);transition:background-color var(--skra-comp-menu-motion-duration) var(--skra-comp-menu-motion-easing)}:host(:hover:not([aria-disabled=true])),:host(:focus-visible:not([aria-disabled=true])){background-color:var(--skra-comp-menu-item-background-hover)}:host(:focus-visible){outline:var(--skra-comp-menu-focus-ring-width) solid var(--skra-comp-menu-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-menu-focus-ring-width))}:host([aria-disabled=true]){color:var(--skra-comp-menu-item-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}}\n"] }]
135
+ }, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:center;gap:var(--skra-comp-menu-item-gap);inline-size:100%;min-block-size:var(--skra-comp-menu-item-min-block-size);margin:0;box-sizing:border-box;padding-block:var(--skra-comp-menu-item-padding-block);padding-inline:var(--skra-comp-menu-item-padding-inline);appearance:none;background:transparent;border:0;color:var(--skra-comp-menu-item-foreground);text-align:start;cursor:pointer;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);transition:background-color var(--skra-comp-menu-motion-duration) var(--skra-comp-menu-motion-easing)}@media(hover:hover)and (pointer:fine){:host(:hover:not([aria-disabled=true])){background-color:var(--skra-comp-menu-item-background-hover)}}:host(:focus-visible:not([aria-disabled=true])){background-color:var(--skra-comp-menu-item-background-hover)}:host(:focus-visible){outline:var(--skra-comp-menu-focus-ring-width) solid var(--skra-comp-menu-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-menu-focus-ring-width))}:host([aria-disabled=true]){color:var(--skra-comp-menu-item-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}}\n"] }]
130
136
  }], ctorParameters: () => [] });
131
137
 
132
138
  /**
@@ -142,11 +148,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
142
148
  * <button skraButton popovertarget="actions" aria-haspopup="menu">Actions</button>
143
149
  * <skra-menu id="actions">
144
150
  * <button skraMenuItem (click)="edit()">Edit</button>
145
- * <button skraMenuItem disabled (click)="archive()">Archive</button>
151
+ * <button skraMenuItem aria-disabled="true" (click)="archive()">Archive</button>
146
152
  * <button skraMenuItem (click)="remove()">Delete</button>
147
153
  * </skra-menu>
148
154
  *
149
- * Forge adds, on top of the Popover substrate: the `role="menu"` keyboard model via `SkraMenuKeyboard`
155
+ * A disabled item is `aria-disabled="true"` set by the CONSUMER — never native `disabled` (boundary
156
+ * #9, native-attr-first): the item stays focusable and in the roving order per APG, and a
157
+ * capture-phase guard on the panel blocks activation. Native `disabled` would keep it in the roving
158
+ * order but make `focus()` a no-op, so arrow navigation would silently dead-end on that row.
159
+ *
160
+ * Skra adds, on top of the Popover substrate: the `role="menu"` keyboard model via `SkraMenuKeyboard`
150
161
  * (CDK `FocusKeyManager` — Down/Up roving + wrap, Home/End, type-ahead, Tab-dismiss), **focus moving
151
162
  * INTO the menu on open** (a composite widget — unlike non-modal Popover; the per-component ADR 0044
152
163
  * §3 rule-8 decision), and the trigger's disclosure ARIA (`aria-haspopup="menu"` / `aria-controls` /
@@ -164,9 +175,10 @@ class SkraMenu {
164
175
  host = inject(ElementRef);
165
176
  renderer = inject(Renderer2);
166
177
  keyboard = new SkraMenuKeyboard();
167
- /** The consumer's `[popovertarget]` button, resolved once (lazily-idempotent via `resolved`). */
178
+ /** The consumer's `[popovertarget]` button; resolution is retried until it succeeds. */
168
179
  trigger = null;
169
- resolved = false;
180
+ /** Latches the dev warning, NOT the resolution — see `ensureTrigger()`. */
181
+ warned = false;
170
182
  positioner;
171
183
  constructor() {
172
184
  // Feed the controller whenever the projected item set changes (signal → array snapshot rebuild).
@@ -239,16 +251,22 @@ class SkraMenu {
239
251
  }
240
252
  /**
241
253
  * Resolve the `[popovertarget]` trigger and establish the menu disclosure ARIA on it (sanctioned a11y
242
- * wiring, ADR 013-style — not style mutation). Idempotent. Returns the trigger (or null for an orphan
243
- * menu, dev-warned once).
254
+ * wiring, ADR 013-style — not style mutation). Returns the trigger (or null for an orphan menu,
255
+ * dev-warned once).
256
+ *
257
+ * Idempotent on SUCCESS only — see the same note on `SkraPopover.ensureTrigger()`. Latching on
258
+ * failure would permanently strand a trigger rendered behind an `@if` / lazy route / `@defer`:
259
+ * no disclosure ARIA, and `onOpen()` bails on the null anchor so the panel opens unpositioned at
260
+ * viewport 0,0 — the exact signature of impl-finding #1 in the spec. The dev warning latches
261
+ * separately via `warned`.
244
262
  */
245
263
  ensureTrigger() {
246
- if (this.resolved)
264
+ if (this.trigger)
247
265
  return this.trigger;
248
- this.resolved = true;
249
266
  const id = this.host.nativeElement.id;
250
267
  if (!id) {
251
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
268
+ if (!this.warned && (typeof ngDevMode === 'undefined' || ngDevMode)) {
269
+ this.warned = true;
252
270
  console.warn('[skra-menu] has no `id` — it cannot be targeted by a `popovertarget` trigger and the ' +
253
271
  'disclosure ARIA (aria-haspopup/aria-controls/aria-expanded) cannot be wired. Give the ' +
254
272
  'menu an id and point a button at it: ' +
@@ -256,11 +274,17 @@ class SkraMenu {
256
274
  }
257
275
  return null;
258
276
  }
277
+ // Scope to this node's own root, not `document`: under the ADR 012 §5 delivery contract both
278
+ // trigger and panel live inside a shadow root, where a document-rooted query finds nothing.
279
+ // `getRootNode()` returns `document` in the light-DOM case, so this is strictly a widening.
280
+ //
259
281
  // Match by attribute value (no escaping; robust to special chars; `CSS.escape` is not universal).
282
+ const root = this.host.nativeElement.getRootNode();
260
283
  this.trigger =
261
- Array.from(document.querySelectorAll('[popovertarget]')).find((el) => el.getAttribute('popovertarget') === id) ?? null;
284
+ Array.from(root.querySelectorAll('[popovertarget]')).find((el) => el.getAttribute('popovertarget') === id) ?? null;
262
285
  if (!this.trigger) {
263
- if (typeof ngDevMode === 'undefined' || ngDevMode) {
286
+ if (!this.warned && (typeof ngDevMode === 'undefined' || ngDevMode)) {
287
+ this.warned = true;
264
288
  console.warn(`[skra-menu] no trigger found with [popovertarget="${id}"] — the menu is unreachable and ` +
265
289
  'has no element to carry aria-haspopup/aria-controls/aria-expanded. Add a focusable trigger ' +
266
290
  'button with the matching popovertarget.');
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-menu.mjs","sources":["../../../../libs/ui/menu/src/lib/menu/menu-keyboard.ts","../../../../libs/ui/menu/src/lib/menu/menu-types.ts","../../../../libs/ui/menu/src/lib/menu/menu-item.ts","../../../../libs/ui/menu/src/lib/menu/menu.ts","../../../../libs/ui/menu/src/skra-ui-menu.ts"],"sourcesContent":["import { FocusKeyManager } from '@angular/cdk/a11y';\r\n\r\nimport type { SkraMenuKeyboardItem } from './menu-types';\r\n\r\n/**\r\n * SkraMenuKeyboard — the WAI-ARIA APG Menu keyboard model, confined to ONE file.\r\n *\r\n * This is the **only** module in Forge that imports `@angular/cdk`. It wraps CDK `FocusKeyManager`\r\n * (roving REAL focus — the APG-canonical menu model, NOT `aria-activedescendant`) so the engine is an\r\n * implementation detail: swapping it (e.g. to a hand-rolled controller) is a one-file change with zero\r\n * impact on `SkraMenu` / `SkraMenuItem` — exactly as `SkraPositioner` wraps `@floating-ui/dom`\r\n * (ADR 0044 §3 rule 5; recorded in §7, 2026-06-07).\r\n *\r\n * Owns: Down/Up roving (wrap), Home/End, type-ahead, and Tab→dismiss. Enter/Space (native button\r\n * activation) and Escape + light-dismiss (`popover=\"auto\"`) stay platform-owned — the controller never\r\n * touches them.\r\n */\r\nexport class SkraMenuKeyboard {\r\n private manager?: FocusKeyManager<SkraMenuKeyboardItem>;\r\n private items: SkraMenuKeyboardItem[] = [];\r\n private tabOutHandler?: () => void;\r\n\r\n /** Register the APG \"Tab dismisses the menu\" callback (fired by `FocusKeyManager.tabOut`). */\r\n onTabOut(handler: () => void): void {\r\n this.tabOutHandler = handler;\r\n }\r\n\r\n /**\r\n * (Re)build the manager from the current projected item set. Called from an `effect` on the menu's\r\n * signal `contentChildren` — a passed array is a static snapshot (it does not auto-track like a live\r\n * `QueryList`), so the manager is rebuilt whenever the item set changes (the documented signal↔CDK seam).\r\n */\r\n setItems(items: readonly SkraMenuKeyboardItem[]): void {\r\n this.items = [...items];\r\n this.manager?.destroy();\r\n this.manager = new FocusKeyManager<SkraMenuKeyboardItem>(this.items)\r\n .withWrap()\r\n .withTypeAhead()\r\n .withHomeAndEnd()\r\n // Disabled items stay in the roving order (APG focusable-but-inert — discoverable); activation is\r\n // blocked on the item itself. `() => false` also stops `FocusKeyManager` from reading `item.disabled`\r\n // (which on our signal-input component would be a truthy function).\r\n .skipPredicate(() => false);\r\n this.manager.tabOut.subscribe(() => this.tabOutHandler?.());\r\n }\r\n\r\n /** Delegate Up/Down/Home/End/type-ahead. Enter/Space/Escape are intentionally left to the platform. */\r\n onKeydown(event: KeyboardEvent): void {\r\n this.manager?.onKeydown(event);\r\n }\r\n\r\n /** Move roving focus to the first ENABLED item (APG: focus enters the menu on open). */\r\n focusFirst(): void {\r\n if (!this.manager || this.items.length === 0) return;\r\n const firstEnabled = this.items.findIndex((item) => !item.isDisabled());\r\n this.manager.setActiveItem(firstEnabled >= 0 ? firstEnabled : 0);\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 { InjectionToken } from '@angular/core';\r\n\r\n/**\r\n * The item shape the menu keyboard controller drives. Structurally a CDK `FocusableOption`\r\n * (`focus()`), plus the menu's own `getLabel()` (type-ahead) and `isDisabled()` (focusable-but-inert\r\n * roving). Declared HERE — cdk-free — so the only `@angular/cdk` importer stays `menu-keyboard.ts`.\r\n */\r\nexport interface SkraMenuKeyboardItem {\r\n focus(): void;\r\n getLabel(): string;\r\n isDisabled(): boolean;\r\n}\r\n\r\n/** What a `skraMenuItem` needs from its `skra-menu` — narrow contract that breaks the menu↔item cycle. */\r\nexport interface SkraMenuPanel {\r\n /** Dismiss the menu after an item activates (native `hidePopover()` → focus returns to the trigger). */\r\n requestClose(): void;\r\n}\r\n\r\n/**\r\n * DI token a `skra-menu` provides (`useExisting`) and a `button[skraMenuItem]` injects. A token\r\n * (not the `SkraMenu` class) so the item file never imports the menu file — no runtime import cycle.\r\n */\r\nexport const SKRA_MENU = new InjectionToken<SkraMenuPanel>('SKRA_MENU');\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n inject,\r\n} from '@angular/core';\r\n\r\nimport { SKRA_MENU, type SkraMenuKeyboardItem } from './menu-types';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraMenuItem — a single command in a `skra-menu`, a Component on the native command host\r\n * `button[skraMenuItem]` (ADR 012/040: a `<button>` is the right semantic — Enter/Space→click +\r\n * focusability for free; its implicit role is overridden to `role=\"menuitem\"` per WAI-ARIA APG).\r\n *\r\n * Roving focus: `tabindex=\"-1\"` (the keyboard controller moves real focus). Implements\r\n * `SkraMenuKeyboardItem` (`focus`/`getLabel`/`isDisabled`) so `SkraMenuKeyboard` (CDK `FocusKeyManager`)\r\n * can drive it. On activation it asks the menu to close (native `hidePopover()` → focus returns to the\r\n * trigger).\r\n *\r\n * **Disabled is native-attr-first (boundary #9, ADR 039 precedent): the consumer sets\r\n * `aria-disabled=\"true\"` directly — Forge OBSERVES it, exposing NO `disabled` input.** This (a) keeps a\r\n * disabled item **focusable/discoverable** in the roving order (APG) — native `disabled` would remove it\r\n * from focus, and (b) avoids a Forge input shadowing the native `disabled` attribute. Styling keys off\r\n * `:host([aria-disabled=\"true\"])`; activation is blocked here.\r\n *\r\n * Full contract: adr/specs/component-menu-spec.md.\r\n */\r\n@Component({\r\n selector: 'button[skraMenuItem]',\r\n standalone: true,\r\n exportAs: 'skraMenuItem',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './menu-item.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'menuitem',\r\n type: 'button', // never an implicit submit if the menu sits inside a <form>\r\n tabindex: '-1', // roving — focus is moved programmatically by SkraMenuKeyboard\r\n '(click)': 'onActivate($event)',\r\n },\r\n})\r\nexport class SkraMenuItem implements SkraMenuKeyboardItem {\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly menu = inject(SKRA_MENU, { optional: true });\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.menu) {\r\n console.warn(\r\n '[skraMenuItem] has no <skra-menu> ancestor — it is not registered with any keyboard ' +\r\n 'controller and cannot close a menu on activation. Project it inside a <skra-menu>.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n // ── SkraMenuKeyboardItem (driven by SkraMenuKeyboard / CDK FocusKeyManager) ──\r\n focus(): void {\r\n this.host.nativeElement.focus();\r\n }\r\n getLabel(): string {\r\n return (this.host.nativeElement.textContent ?? '').trim();\r\n }\r\n /** Soft-disabled = the consumer's `aria-disabled=\"true\"` (native-attr-first); read live (no input). */\r\n isDisabled(): boolean {\r\n return this.host.nativeElement.getAttribute('aria-disabled') === 'true';\r\n }\r\n\r\n protected onActivate(event: MouseEvent): void {\r\n if (this.isDisabled()) {\r\n // Soft-disabled: block the native default AND the consumer's own (click) on this same host\r\n // (the host listener runs first — Material's MatMenuItem precedent).\r\n event.preventDefault();\r\n event.stopImmediatePropagation();\r\n return;\r\n }\r\n // Activating a command closes the menu (APG). The consumer's (click) handler runs independently.\r\n this.menu?.requestClose();\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n ElementRef,\r\n Renderer2,\r\n ViewEncapsulation,\r\n afterNextRender,\r\n contentChildren,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport {\r\n _attachPositioner,\r\n type SkraPlacement,\r\n type _PositionerHandle,\r\n} from '@skra/ui/core';\r\nimport { SkraMenuKeyboard } from './menu-keyboard';\r\nimport { SkraMenuItem } from './menu-item';\r\nimport { SKRA_MENU, type SkraMenuPanel } from './menu-types';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraMenu — a WAI-ARIA APG **Menu Button** menu: a homogeneous set of commands anchored to a\r\n * trigger, navigated as one composite widget with arrow keys, where activating a command closes it.\r\n * Rendered in the browser TOP LAYER via the native Popover API (`popover=\"auto\"`), per ADR 0044.\r\n *\r\n * SHAPE (scope 2026-06-07): a Component on the PANEL with projected `button[skraMenuItem]` children\r\n * (the Popover model, ADR 040) — NOT a directive on the trigger, NOT a data-driven `[items]` array.\r\n * The trigger is the consumer's own button linked by the native `popovertarget` attribute; toggle,\r\n * light-dismiss and Escape are platform-owned. The consumer MUST give `<skra-menu>` an `id`.\r\n *\r\n * <button skraButton popovertarget=\"actions\" aria-haspopup=\"menu\">Actions</button>\r\n * <skra-menu id=\"actions\">\r\n * <button skraMenuItem (click)=\"edit()\">Edit</button>\r\n * <button skraMenuItem disabled (click)=\"archive()\">Archive</button>\r\n * <button skraMenuItem (click)=\"remove()\">Delete</button>\r\n * </skra-menu>\r\n *\r\n * Forge adds, on top of the Popover substrate: the `role=\"menu\"` keyboard model via `SkraMenuKeyboard`\r\n * (CDK `FocusKeyManager` — Down/Up roving + wrap, Home/End, type-ahead, Tab-dismiss), **focus moving\r\n * INTO the menu on open** (a composite widget — unlike non-modal Popover; the per-component ADR 0044\r\n * §3 rule-8 decision), and the trigger's disclosure ARIA (`aria-haspopup=\"menu\"` / `aria-controls` /\r\n * `aria-expanded`). Side effects on open/close: bind the native `(toggle)` — there is no Forge output\r\n * (native-first; contrast Dialog, whose `<dialog>` has no open event). Context menus (right-click) are\r\n * a recipe with a visible button, never a trigger mode (SRP + WCAG 2.1.1).\r\n *\r\n * Full contract: adr/specs/component-menu-spec.md.\r\n */\r\n@Component({\r\n selector: 'skra-menu',\r\n standalone: true,\r\n exportAs: 'skraMenu',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './menu.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n providers: [{ provide: SKRA_MENU, useExisting: SkraMenu }],\r\n host: {\r\n role: 'menu',\r\n // Native top layer + platform-owned toggle / light-dismiss / Escape / stacking (ADR 0044).\r\n popover: 'auto',\r\n // NOTE: `toggle` and `keydown` are wired IMPERATIVELY in the constructor, NOT as host listeners.\r\n // A consumer template binding `(toggle)` on <skra-menu> (the documented side-effect path) SHADOWS a\r\n // host-metadata `(toggle)` listener for the same event — which would silently break positioning +\r\n // aria-expanded. A raw `addEventListener` is independent of Angular's host/template listener slot, so\r\n // it always fires alongside the consumer's binding.\r\n },\r\n})\r\nexport class SkraMenu implements SkraMenuPanel {\r\n /** Placement intent; `flip`/`shift` adjust at runtime. */\r\n readonly placement = input<SkraPlacement>('bottom');\r\n\r\n private readonly menuItems = contentChildren(SkraMenuItem, {\r\n descendants: true,\r\n });\r\n\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly renderer = inject(Renderer2);\r\n private readonly keyboard = new SkraMenuKeyboard();\r\n\r\n /** The consumer's `[popovertarget]` button, resolved once (lazily-idempotent via `resolved`). */\r\n private trigger: HTMLElement | null = null;\r\n private resolved = false;\r\n private positioner?: _PositionerHandle;\r\n\r\n constructor() {\r\n // Feed the controller whenever the projected item set changes (signal → array snapshot rebuild).\r\n effect(() => this.keyboard.setItems(this.menuItems()));\r\n // APG: Tab/Shift+Tab dismisses the menu; native Tab then proceeds from the trigger.\r\n this.keyboard.onTabOut(() => this.host.nativeElement.hidePopover?.());\r\n\r\n // All imperative DOM wiring lives in afterNextRender — a browser-only hook, so the native listeners\r\n // and the trigger resolution never run on the server (SSR-safe by construction; O-18). The listeners\r\n // attach right after first paint, long before any user interaction can fire them.\r\n afterNextRender(() => {\r\n const el = this.host.nativeElement;\r\n // Gate disabled items at the CAPTURE phase: a component host listener registers AFTER the parent\r\n // template's `(click)` on the same button, so a bubble-phase guard cannot stop the consumer's own\r\n // handler. A capture listener on the menu host fires before the target's listeners — preventing both\r\n // the consumer's `(click)` and the item's `onActivate` for an `aria-disabled` item.\r\n el.addEventListener('click', this.onCaptureClick, true);\r\n // Imperative (NOT host-metadata) so a consumer `(toggle)` binding does not shadow them — see host {}.\r\n el.addEventListener('toggle', this.onToggleNative);\r\n el.addEventListener('keydown', this.onKeydownNative);\r\n\r\n // Resolve + wire the trigger after the view exists (it may be a later sibling), so the disclosure\r\n // relationship (aria-haspopup + aria-controls + aria-expanded=\"false\") is present before first open.\r\n this.ensureTrigger();\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) this.warnIfEmpty();\r\n });\r\n inject(DestroyRef).onDestroy(() => this.teardown());\r\n }\r\n\r\n /** SKRA_MENU contract — close on item activation (native focus-return to the trigger). */\r\n requestClose(): void {\r\n this.host.nativeElement.hidePopover?.();\r\n }\r\n\r\n /** Capture-phase guard: block clicks on an `aria-disabled` item before they reach its listeners. */\r\n private readonly onCaptureClick = (event: Event): void => {\r\n const item = (event.target as HTMLElement | null)?.closest?.(\r\n '[skraMenuItem]',\r\n );\r\n if (item?.getAttribute('aria-disabled') === 'true') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n };\r\n\r\n // ── Toggle / keydown (imperative native listeners — see host {} note) ─────────\r\n private readonly onToggleNative = (event: Event): void => {\r\n if ((event as ToggleEvent).newState === 'open') this.onOpen();\r\n else this.onClose();\r\n };\r\n\r\n private readonly onKeydownNative = (event: Event): void => {\r\n this.keyboard.onKeydown(event as KeyboardEvent);\r\n };\r\n\r\n private onOpen(): void {\r\n const anchor = this.ensureTrigger(); // safety net if afterNextRender has not yet run\r\n if (anchor) {\r\n this.renderer.setAttribute(anchor, 'aria-expanded', 'true');\r\n this.positioner?.destroy();\r\n this.positioner = _attachPositioner(\r\n anchor,\r\n this.host.nativeElement,\r\n () => ({\r\n placement: this.placement(),\r\n offset: this.cssLenPx('--skra-comp-menu-offset'),\r\n viewportPadding: this.cssLenPx('--skra-comp-menu-viewport-padding'),\r\n }),\r\n );\r\n }\r\n // Focus enters the menu (APG Menu Button) regardless of how it opened — unlike non-modal Popover.\r\n this.keyboard.focusFirst();\r\n }\r\n\r\n private onClose(): void {\r\n if (this.trigger) {\r\n this.renderer.setAttribute(this.trigger, 'aria-expanded', 'false');\r\n }\r\n this.positioner?.destroy();\r\n this.positioner = undefined;\r\n }\r\n\r\n /**\r\n * Resolve the `[popovertarget]` trigger and establish the menu disclosure ARIA on it (sanctioned a11y\r\n * wiring, ADR 013-style — not style mutation). Idempotent. Returns the trigger (or null for an orphan\r\n * menu, dev-warned once).\r\n */\r\n private ensureTrigger(): HTMLElement | null {\r\n if (this.resolved) return this.trigger;\r\n this.resolved = true;\r\n\r\n const id = this.host.nativeElement.id;\r\n if (!id) {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n console.warn(\r\n '[skra-menu] has no `id` — it cannot be targeted by a `popovertarget` trigger and the ' +\r\n 'disclosure ARIA (aria-haspopup/aria-controls/aria-expanded) cannot be wired. Give the ' +\r\n 'menu an id and point a button at it: ' +\r\n '<button popovertarget=\"my-id\" aria-haspopup=\"menu\">…</button> <skra-menu id=\"my-id\">…',\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n // Match by attribute value (no escaping; robust to special chars; `CSS.escape` is not universal).\r\n this.trigger =\r\n Array.from(\r\n document.querySelectorAll<HTMLElement>('[popovertarget]'),\r\n ).find((el) => el.getAttribute('popovertarget') === id) ?? null;\r\n if (!this.trigger) {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n console.warn(\r\n `[skra-menu] no trigger found with [popovertarget=\"${id}\"] — the menu is unreachable and ` +\r\n 'has no element to carry aria-haspopup/aria-controls/aria-expanded. Add a focusable trigger ' +\r\n 'button with the matching popovertarget.',\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n // Establish the Menu Button relationship before the first open (APG; aria-haspopup distinguishes a\r\n // menu from Popover's generic disclosure).\r\n this.renderer.setAttribute(this.trigger, 'aria-haspopup', 'menu');\r\n this.renderer.setAttribute(this.trigger, 'aria-controls', id);\r\n this.renderer.setAttribute(this.trigger, 'aria-expanded', 'false');\r\n return this.trigger;\r\n }\r\n\r\n /** Read a length comp token (px/rem) off the host computed style for the positioner. */\r\n private cssLenPx(prop: string): number {\r\n const raw = getComputedStyle(this.host.nativeElement)\r\n .getPropertyValue(prop)\r\n .trim();\r\n if (raw.endsWith('px')) return parseFloat(raw);\r\n if (raw.endsWith('rem')) {\r\n const rootFontSize =\r\n parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\r\n return parseFloat(raw) * rootFontSize;\r\n }\r\n return parseFloat(raw) || 0;\r\n }\r\n\r\n /** Dev-only nudge: a role=\"menu\" with no menuitems is invalid — a link-list/content panel is a Popover. */\r\n private warnIfEmpty(): void {\r\n if (this.menuItems().length === 0) {\r\n console.warn(\r\n '[skra-menu] has no `button[skraMenuItem]` children — a `role=\"menu\"` with no menu items is ' +\r\n 'invalid. If this is a panel of arbitrary content or a list of navigation links, use ' +\r\n '<skra-popover> (disclosure) instead — see the Menu-vs-Popover boundary in the spec.',\r\n );\r\n }\r\n }\r\n\r\n private teardown(): void {\r\n const el = this.host.nativeElement;\r\n el.removeEventListener('click', this.onCaptureClick, true);\r\n el.removeEventListener('toggle', this.onToggleNative);\r\n el.removeEventListener('keydown', this.onKeydownNative);\r\n this.keyboard.destroy();\r\n this.positioner?.destroy();\r\n if (this.trigger) {\r\n this.renderer.removeAttribute(this.trigger, 'aria-haspopup');\r\n this.renderer.removeAttribute(this.trigger, 'aria-expanded');\r\n this.renderer.removeAttribute(this.trigger, 'aria-controls');\r\n }\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-menu.mjs","sources":["../../../../libs/ui/menu/src/lib/menu/menu-keyboard.ts","../../../../libs/ui/menu/src/lib/menu/menu-types.ts","../../../../libs/ui/menu/src/lib/menu/menu-item.ts","../../../../libs/ui/menu/src/lib/menu/menu.ts","../../../../libs/ui/menu/src/skra-ui-menu.ts"],"sourcesContent":["import { FocusKeyManager } from '@angular/cdk/a11y';\r\n\r\nimport type { SkraMenuKeyboardItem } from './menu-types';\r\n\r\n/**\r\n * SkraMenuKeyboard — the WAI-ARIA APG Menu keyboard model, confined to ONE file.\r\n *\r\n * This is the only module in `@skra/ui/menu` that imports `@angular/cdk`. ADR 0044 §7 was later\r\n * generalized library-wide to \"one swappable `*-keyboard.ts` per APG pattern\", so there are now\r\n * three such files — this one, `core/select/listbox-keyboard.ts` (`ActiveDescendantKeyManager`) and\r\n * `tabs/tabs-keyboard.ts` — enforced by `tools/cdk-confinement-validator.mjs`. It wraps CDK `FocusKeyManager`\r\n * (roving REAL focus — the APG-canonical menu model, NOT `aria-activedescendant`) so the engine is an\r\n * implementation detail: swapping it (e.g. to a hand-rolled controller) is a one-file change with zero\r\n * impact on `SkraMenu` / `SkraMenuItem` — exactly as `SkraPositioner` wraps `@floating-ui/dom`\r\n * (ADR 0044 §3 rule 5; recorded in §7, 2026-06-07).\r\n *\r\n * Owns: Down/Up roving (wrap), Home/End, type-ahead, and Tab→dismiss. Enter/Space (native button\r\n * activation) and Escape + light-dismiss (`popover=\"auto\"`) stay platform-owned — the controller never\r\n * touches them.\r\n */\r\nexport class SkraMenuKeyboard {\r\n private manager?: FocusKeyManager<SkraMenuKeyboardItem>;\r\n private items: SkraMenuKeyboardItem[] = [];\r\n private tabOutHandler?: () => void;\r\n\r\n /** Register the APG \"Tab dismisses the menu\" callback (fired by `FocusKeyManager.tabOut`). */\r\n onTabOut(handler: () => void): void {\r\n this.tabOutHandler = handler;\r\n }\r\n\r\n /**\r\n * (Re)build the manager from the current projected item set. Called from an `effect` on the menu's\r\n * signal `contentChildren` — a passed array is a static snapshot (it does not auto-track like a live\r\n * `QueryList`), so the manager is rebuilt whenever the item set changes (the documented signal↔CDK seam).\r\n */\r\n setItems(items: readonly SkraMenuKeyboardItem[]): void {\r\n this.items = [...items];\r\n this.manager?.destroy();\r\n this.manager = new FocusKeyManager<SkraMenuKeyboardItem>(this.items)\r\n .withWrap()\r\n .withTypeAhead()\r\n .withHomeAndEnd()\r\n // Disabled items stay in the roving order (APG focusable-but-inert — discoverable); activation is\r\n // blocked on the item itself. `() => false` also stops `FocusKeyManager` from reading `item.disabled`\r\n // (which on our signal-input component would be a truthy function).\r\n .skipPredicate(() => false);\r\n this.manager.tabOut.subscribe(() => this.tabOutHandler?.());\r\n }\r\n\r\n /** Delegate Up/Down/Home/End/type-ahead. Enter/Space/Escape are intentionally left to the platform. */\r\n onKeydown(event: KeyboardEvent): void {\r\n this.manager?.onKeydown(event);\r\n }\r\n\r\n /** Move roving focus to the first ENABLED item (APG: focus enters the menu on open). */\r\n focusFirst(): void {\r\n if (!this.manager || this.items.length === 0) return;\r\n const firstEnabled = this.items.findIndex((item) => !item.isDisabled());\r\n this.manager.setActiveItem(firstEnabled >= 0 ? firstEnabled : 0);\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 { InjectionToken } from '@angular/core';\n\n/**\n * The item shape the menu keyboard controller drives. Structurally a CDK `FocusableOption`\n * (`focus()`), plus the menu's own `getLabel()` (type-ahead) and `isDisabled()` (focusable-but-inert\n * roving). Declared HERE — cdk-free — so the only `@angular/cdk` importer stays `menu-keyboard.ts`.\n */\nexport interface SkraMenuKeyboardItem {\n focus(): void;\n getLabel(): string;\n isDisabled(): boolean;\n}\n\n/** What a `skraMenuItem` needs from its `skra-menu` — narrow contract that breaks the menu↔item cycle. */\nexport interface SkraMenuPanel {\n /** Dismiss the menu after an item activates (native `hidePopover()` → focus returns to the trigger). */\n requestClose(): void;\n}\n\n/**\n * DI token a `skra-menu` provides (`useExisting`) and a `button[skraMenuItem]` injects. A token\n * (not the `SkraMenu` class) so the item file never imports the menu file — no runtime import cycle.\n */\nexport const SKRA_MENU = new InjectionToken<SkraMenuPanel>('SKRA_MENU');\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n inject,\r\n} from '@angular/core';\r\n\r\nimport { SKRA_MENU, type SkraMenuKeyboardItem } from './menu-types';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraMenuItem — a single command in a `skra-menu`, a Component on the native command host\r\n * `button[skraMenuItem]` (ADR 012/040: a `<button>` is the right semantic — Enter/Space→click +\r\n * focusability for free; its implicit role is overridden to `role=\"menuitem\"` per WAI-ARIA APG).\r\n *\r\n * Roving focus: `tabindex=\"-1\"` (the keyboard controller moves real focus). Implements\r\n * `SkraMenuKeyboardItem` (`focus`/`getLabel`/`isDisabled`) so `SkraMenuKeyboard` (CDK `FocusKeyManager`)\r\n * can drive it. On activation it asks the menu to close (native `hidePopover()` → focus returns to the\r\n * trigger).\r\n *\r\n * **Disabled is native-attr-first (boundary #9, ADR 039 precedent): the consumer sets\r\n * `aria-disabled=\"true\"` directly — Forge OBSERVES it, exposing NO `disabled` input.** This (a) keeps a\r\n * disabled item **focusable/discoverable** in the roving order (APG) — native `disabled` would remove it\r\n * from focus, and (b) avoids a Forge input shadowing the native `disabled` attribute. Styling keys off\r\n * `:host([aria-disabled=\"true\"])`; activation is blocked here.\r\n *\r\n * Full contract: adr/specs/component-menu-spec.md.\r\n */\r\n@Component({\r\n selector: 'button[skraMenuItem]',\r\n standalone: true,\r\n exportAs: 'skraMenuItem',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './menu-item.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'menuitem',\r\n type: 'button', // never an implicit submit if the menu sits inside a <form>\r\n tabindex: '-1', // roving — focus is moved programmatically by SkraMenuKeyboard\r\n '(click)': 'onActivate($event)',\r\n },\r\n})\r\nexport class SkraMenuItem implements SkraMenuKeyboardItem {\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly menu = inject(SKRA_MENU, { optional: true });\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.menu) {\r\n console.warn(\r\n '[skraMenuItem] has no <skra-menu> ancestor — it is not registered with any keyboard ' +\r\n 'controller and cannot close a menu on activation. Project it inside a <skra-menu>.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n // ── SkraMenuKeyboardItem (driven by SkraMenuKeyboard / CDK FocusKeyManager) ──\r\n focus(): void {\r\n this.host.nativeElement.focus();\r\n }\r\n getLabel(): string {\r\n return (this.host.nativeElement.textContent ?? '').trim();\r\n }\r\n /** Soft-disabled = the consumer's `aria-disabled=\"true\"` (native-attr-first); read live (no input). */\r\n isDisabled(): boolean {\r\n return this.host.nativeElement.getAttribute('aria-disabled') === 'true';\r\n }\r\n\r\n protected onActivate(event: MouseEvent): void {\r\n if (this.isDisabled()) {\r\n // Soft-disabled: block the native default. This is a SECOND line of defence only — it cannot\r\n // stop the consumer's own (click) on this same host, because a component host listener\r\n // registers AFTER the parent template's binding, so this bubble-phase handler runs too late.\r\n // The capture-phase guard on the panel (`SkraMenu`) is what actually blocks activation, for\r\n // both pointer and keyboard (Enter/Space produce a UA-synthesized click). Do not delete it.\r\n event.preventDefault();\r\n event.stopImmediatePropagation();\r\n return;\r\n }\r\n // Activating a command closes the menu (APG). The consumer's (click) handler runs independently.\r\n this.menu?.requestClose();\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n ElementRef,\r\n Renderer2,\r\n ViewEncapsulation,\r\n afterNextRender,\r\n contentChildren,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport {\r\n _attachPositioner,\r\n type SkraPlacement,\r\n type _PositionerHandle,\r\n} from '@skra/ui/core';\r\nimport { SkraMenuKeyboard } from './menu-keyboard';\r\nimport { SkraMenuItem } from './menu-item';\r\nimport { SKRA_MENU, type SkraMenuPanel } from './menu-types';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraMenu — a WAI-ARIA APG **Menu Button** menu: a homogeneous set of commands anchored to a\r\n * trigger, navigated as one composite widget with arrow keys, where activating a command closes it.\r\n * Rendered in the browser TOP LAYER via the native Popover API (`popover=\"auto\"`), per ADR 0044.\r\n *\r\n * SHAPE (scope 2026-06-07): a Component on the PANEL with projected `button[skraMenuItem]` children\r\n * (the Popover model, ADR 040) — NOT a directive on the trigger, NOT a data-driven `[items]` array.\r\n * The trigger is the consumer's own button linked by the native `popovertarget` attribute; toggle,\r\n * light-dismiss and Escape are platform-owned. The consumer MUST give `<skra-menu>` an `id`.\r\n *\r\n * <button skraButton popovertarget=\"actions\" aria-haspopup=\"menu\">Actions</button>\r\n * <skra-menu id=\"actions\">\r\n * <button skraMenuItem (click)=\"edit()\">Edit</button>\r\n * <button skraMenuItem aria-disabled=\"true\" (click)=\"archive()\">Archive</button>\r\n * <button skraMenuItem (click)=\"remove()\">Delete</button>\r\n * </skra-menu>\r\n *\r\n * A disabled item is `aria-disabled=\"true\"` set by the CONSUMER — never native `disabled` (boundary\r\n * #9, native-attr-first): the item stays focusable and in the roving order per APG, and a\r\n * capture-phase guard on the panel blocks activation. Native `disabled` would keep it in the roving\r\n * order but make `focus()` a no-op, so arrow navigation would silently dead-end on that row.\r\n *\r\n * Skra adds, on top of the Popover substrate: the `role=\"menu\"` keyboard model via `SkraMenuKeyboard`\r\n * (CDK `FocusKeyManager` — Down/Up roving + wrap, Home/End, type-ahead, Tab-dismiss), **focus moving\r\n * INTO the menu on open** (a composite widget — unlike non-modal Popover; the per-component ADR 0044\r\n * §3 rule-8 decision), and the trigger's disclosure ARIA (`aria-haspopup=\"menu\"` / `aria-controls` /\r\n * `aria-expanded`). Side effects on open/close: bind the native `(toggle)` — there is no Forge output\r\n * (native-first; contrast Dialog, whose `<dialog>` has no open event). Context menus (right-click) are\r\n * a recipe with a visible button, never a trigger mode (SRP + WCAG 2.1.1).\r\n *\r\n * Full contract: adr/specs/component-menu-spec.md.\r\n */\r\n@Component({\r\n selector: 'skra-menu',\r\n standalone: true,\r\n exportAs: 'skraMenu',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './menu.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n providers: [{ provide: SKRA_MENU, useExisting: SkraMenu }],\r\n host: {\r\n role: 'menu',\r\n // Native top layer + platform-owned toggle / light-dismiss / Escape / stacking (ADR 0044).\r\n popover: 'auto',\r\n // NOTE: `toggle` and `keydown` are wired IMPERATIVELY in the constructor, NOT as host listeners.\r\n // A consumer template binding `(toggle)` on <skra-menu> (the documented side-effect path) SHADOWS a\r\n // host-metadata `(toggle)` listener for the same event — which would silently break positioning +\r\n // aria-expanded. A raw `addEventListener` is independent of Angular's host/template listener slot, so\r\n // it always fires alongside the consumer's binding.\r\n },\r\n})\r\nexport class SkraMenu implements SkraMenuPanel {\r\n /** Placement intent; `flip`/`shift` adjust at runtime. */\r\n readonly placement = input<SkraPlacement>('bottom');\r\n\r\n private readonly menuItems = contentChildren(SkraMenuItem, {\r\n descendants: true,\r\n });\r\n\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n private readonly renderer = inject(Renderer2);\r\n private readonly keyboard = new SkraMenuKeyboard();\r\n\r\n /** The consumer's `[popovertarget]` button; resolution is retried until it succeeds. */\r\n private trigger: HTMLElement | null = null;\r\n /** Latches the dev warning, NOT the resolution — see `ensureTrigger()`. */\r\n private warned = false;\r\n private positioner?: _PositionerHandle;\r\n\r\n constructor() {\r\n // Feed the controller whenever the projected item set changes (signal → array snapshot rebuild).\r\n effect(() => this.keyboard.setItems(this.menuItems()));\r\n // APG: Tab/Shift+Tab dismisses the menu; native Tab then proceeds from the trigger.\r\n this.keyboard.onTabOut(() => this.host.nativeElement.hidePopover?.());\r\n\r\n // All imperative DOM wiring lives in afterNextRender — a browser-only hook, so the native listeners\r\n // and the trigger resolution never run on the server (SSR-safe by construction; O-18). The listeners\r\n // attach right after first paint, long before any user interaction can fire them.\r\n afterNextRender(() => {\r\n const el = this.host.nativeElement;\r\n // Gate disabled items at the CAPTURE phase: a component host listener registers AFTER the parent\r\n // template's `(click)` on the same button, so a bubble-phase guard cannot stop the consumer's own\r\n // handler. A capture listener on the menu host fires before the target's listeners — preventing both\r\n // the consumer's `(click)` and the item's `onActivate` for an `aria-disabled` item.\r\n el.addEventListener('click', this.onCaptureClick, true);\r\n // Imperative (NOT host-metadata) so a consumer `(toggle)` binding does not shadow them — see host {}.\r\n el.addEventListener('toggle', this.onToggleNative);\r\n el.addEventListener('keydown', this.onKeydownNative);\r\n\r\n // Resolve + wire the trigger after the view exists (it may be a later sibling), so the disclosure\r\n // relationship (aria-haspopup + aria-controls + aria-expanded=\"false\") is present before first open.\r\n this.ensureTrigger();\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) this.warnIfEmpty();\r\n });\r\n inject(DestroyRef).onDestroy(() => this.teardown());\r\n }\r\n\r\n /** SKRA_MENU contract — close on item activation (native focus-return to the trigger). */\r\n requestClose(): void {\r\n this.host.nativeElement.hidePopover?.();\r\n }\r\n\r\n /** Capture-phase guard: block clicks on an `aria-disabled` item before they reach its listeners. */\r\n private readonly onCaptureClick = (event: Event): void => {\r\n const item = (event.target as HTMLElement | null)?.closest?.(\r\n '[skraMenuItem]',\r\n );\r\n if (item?.getAttribute('aria-disabled') === 'true') {\r\n event.preventDefault();\r\n event.stopPropagation();\r\n }\r\n };\r\n\r\n // ── Toggle / keydown (imperative native listeners — see host {} note) ─────────\r\n private readonly onToggleNative = (event: Event): void => {\r\n if ((event as ToggleEvent).newState === 'open') this.onOpen();\r\n else this.onClose();\r\n };\r\n\r\n private readonly onKeydownNative = (event: Event): void => {\r\n this.keyboard.onKeydown(event as KeyboardEvent);\r\n };\r\n\r\n private onOpen(): void {\r\n const anchor = this.ensureTrigger(); // safety net if afterNextRender has not yet run\r\n if (anchor) {\r\n this.renderer.setAttribute(anchor, 'aria-expanded', 'true');\r\n this.positioner?.destroy();\r\n this.positioner = _attachPositioner(\r\n anchor,\r\n this.host.nativeElement,\r\n () => ({\r\n placement: this.placement(),\r\n offset: this.cssLenPx('--skra-comp-menu-offset'),\r\n viewportPadding: this.cssLenPx('--skra-comp-menu-viewport-padding'),\r\n }),\r\n );\r\n }\r\n // Focus enters the menu (APG Menu Button) regardless of how it opened — unlike non-modal Popover.\r\n this.keyboard.focusFirst();\r\n }\r\n\r\n private onClose(): void {\r\n if (this.trigger) {\r\n this.renderer.setAttribute(this.trigger, 'aria-expanded', 'false');\r\n }\r\n this.positioner?.destroy();\r\n this.positioner = undefined;\r\n }\r\n\r\n /**\r\n * Resolve the `[popovertarget]` trigger and establish the menu disclosure ARIA on it (sanctioned a11y\r\n * wiring, ADR 013-style — not style mutation). Returns the trigger (or null for an orphan menu,\r\n * dev-warned once).\r\n *\r\n * Idempotent on SUCCESS only — see the same note on `SkraPopover.ensureTrigger()`. Latching on\r\n * failure would permanently strand a trigger rendered behind an `@if` / lazy route / `@defer`:\r\n * no disclosure ARIA, and `onOpen()` bails on the null anchor so the panel opens unpositioned at\r\n * viewport 0,0 — the exact signature of impl-finding #1 in the spec. The dev warning latches\r\n * separately via `warned`.\r\n */\r\n private ensureTrigger(): HTMLElement | null {\r\n if (this.trigger) return this.trigger;\r\n\r\n const id = this.host.nativeElement.id;\r\n if (!id) {\r\n if (!this.warned && (typeof ngDevMode === 'undefined' || ngDevMode)) {\r\n this.warned = true;\r\n console.warn(\r\n '[skra-menu] has no `id` — it cannot be targeted by a `popovertarget` trigger and the ' +\r\n 'disclosure ARIA (aria-haspopup/aria-controls/aria-expanded) cannot be wired. Give the ' +\r\n 'menu an id and point a button at it: ' +\r\n '<button popovertarget=\"my-id\" aria-haspopup=\"menu\">…</button> <skra-menu id=\"my-id\">…',\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n // Scope to this node's own root, not `document`: under the ADR 012 §5 delivery contract both\r\n // trigger and panel live inside a shadow root, where a document-rooted query finds nothing.\r\n // `getRootNode()` returns `document` in the light-DOM case, so this is strictly a widening.\r\n //\r\n // Match by attribute value (no escaping; robust to special chars; `CSS.escape` is not universal).\r\n const root = this.host.nativeElement.getRootNode() as Document | ShadowRoot;\r\n this.trigger =\r\n Array.from(root.querySelectorAll<HTMLElement>('[popovertarget]')).find(\r\n (el) => el.getAttribute('popovertarget') === id,\r\n ) ?? null;\r\n if (!this.trigger) {\r\n if (!this.warned && (typeof ngDevMode === 'undefined' || ngDevMode)) {\r\n this.warned = true;\r\n console.warn(\r\n `[skra-menu] no trigger found with [popovertarget=\"${id}\"] — the menu is unreachable and ` +\r\n 'has no element to carry aria-haspopup/aria-controls/aria-expanded. Add a focusable trigger ' +\r\n 'button with the matching popovertarget.',\r\n );\r\n }\r\n return null;\r\n }\r\n\r\n // Establish the Menu Button relationship before the first open (APG; aria-haspopup distinguishes a\r\n // menu from Popover's generic disclosure).\r\n this.renderer.setAttribute(this.trigger, 'aria-haspopup', 'menu');\r\n this.renderer.setAttribute(this.trigger, 'aria-controls', id);\r\n this.renderer.setAttribute(this.trigger, 'aria-expanded', 'false');\r\n return this.trigger;\r\n }\r\n\r\n /** Read a length comp token (px/rem) off the host computed style for the positioner. */\r\n private cssLenPx(prop: string): number {\r\n const raw = getComputedStyle(this.host.nativeElement)\r\n .getPropertyValue(prop)\r\n .trim();\r\n if (raw.endsWith('px')) return parseFloat(raw);\r\n if (raw.endsWith('rem')) {\r\n const rootFontSize =\r\n parseFloat(getComputedStyle(document.documentElement).fontSize) || 16;\r\n return parseFloat(raw) * rootFontSize;\r\n }\r\n return parseFloat(raw) || 0;\r\n }\r\n\r\n /** Dev-only nudge: a role=\"menu\" with no menuitems is invalid — a link-list/content panel is a Popover. */\r\n private warnIfEmpty(): void {\r\n if (this.menuItems().length === 0) {\r\n console.warn(\r\n '[skra-menu] has no `button[skraMenuItem]` children — a `role=\"menu\"` with no menu items is ' +\r\n 'invalid. If this is a panel of arbitrary content or a list of navigation links, use ' +\r\n '<skra-popover> (disclosure) instead — see the Menu-vs-Popover boundary in the spec.',\r\n );\r\n }\r\n }\r\n\r\n private teardown(): void {\r\n const el = this.host.nativeElement;\r\n el.removeEventListener('click', this.onCaptureClick, true);\r\n el.removeEventListener('toggle', this.onToggleNative);\r\n el.removeEventListener('keydown', this.onKeydownNative);\r\n this.keyboard.destroy();\r\n this.positioner?.destroy();\r\n if (this.trigger) {\r\n this.renderer.removeAttribute(this.trigger, 'aria-haspopup');\r\n this.renderer.removeAttribute(this.trigger, 'aria-expanded');\r\n this.renderer.removeAttribute(this.trigger, 'aria-controls');\r\n }\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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"}