@skra/ui 0.2.0 → 0.3.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 (88) hide show
  1. package/LICENSE +201 -201
  2. package/NOTICE +7 -7
  3. package/README.md +39 -39
  4. package/consumer-guide/README.md +84 -84
  5. package/consumer-guide/forms-and-binding.md +19 -3
  6. package/consumer-guide/layout.md +19 -0
  7. package/consumer-guide/overlays.md +100 -100
  8. package/consumer-guide/setup-and-gotchas.md +165 -103
  9. package/consumer-guide/theming-and-encapsulation.md +129 -115
  10. package/fesm2022/skra-ui-accordion.mjs +61 -43
  11. package/fesm2022/skra-ui-accordion.mjs.map +1 -1
  12. package/fesm2022/skra-ui-alert.mjs +26 -18
  13. package/fesm2022/skra-ui-alert.mjs.map +1 -1
  14. package/fesm2022/skra-ui-avatar.mjs +12 -8
  15. package/fesm2022/skra-ui-avatar.mjs.map +1 -1
  16. package/fesm2022/skra-ui-badge.mjs +19 -13
  17. package/fesm2022/skra-ui-badge.mjs.map +1 -1
  18. package/fesm2022/skra-ui-button.mjs +28 -19
  19. package/fesm2022/skra-ui-button.mjs.map +1 -1
  20. package/fesm2022/skra-ui-checkbox.mjs +3 -3
  21. package/fesm2022/skra-ui-checkbox.mjs.map +1 -1
  22. package/fesm2022/skra-ui-chip.mjs +15 -11
  23. package/fesm2022/skra-ui-chip.mjs.map +1 -1
  24. package/fesm2022/skra-ui-combobox.mjs +135 -130
  25. package/fesm2022/skra-ui-combobox.mjs.map +1 -1
  26. package/fesm2022/skra-ui-core.mjs +95 -73
  27. package/fesm2022/skra-ui-core.mjs.map +1 -1
  28. package/fesm2022/skra-ui-counter.mjs +9 -6
  29. package/fesm2022/skra-ui-counter.mjs.map +1 -1
  30. package/fesm2022/skra-ui-datepicker.mjs +334 -307
  31. package/fesm2022/skra-ui-datepicker.mjs.map +1 -1
  32. package/fesm2022/skra-ui-dialog.mjs +5 -4
  33. package/fesm2022/skra-ui-dialog.mjs.map +1 -1
  34. package/fesm2022/skra-ui-field.mjs +44 -34
  35. package/fesm2022/skra-ui-field.mjs.map +1 -1
  36. package/fesm2022/skra-ui-icon.mjs +5 -4
  37. package/fesm2022/skra-ui-icon.mjs.map +1 -1
  38. package/fesm2022/skra-ui-input.mjs +53 -12
  39. package/fesm2022/skra-ui-input.mjs.map +1 -1
  40. package/fesm2022/skra-ui-kbd.mjs +3 -3
  41. package/fesm2022/skra-ui-kbd.mjs.map +1 -1
  42. package/fesm2022/skra-ui-layout.mjs +33 -21
  43. package/fesm2022/skra-ui-layout.mjs.map +1 -1
  44. package/fesm2022/skra-ui-link.mjs +3 -3
  45. package/fesm2022/skra-ui-link.mjs.map +1 -1
  46. package/fesm2022/skra-ui-loading-indicator.mjs +3 -3
  47. package/fesm2022/skra-ui-loading-indicator.mjs.map +1 -1
  48. package/fesm2022/skra-ui-menu.mjs +8 -7
  49. package/fesm2022/skra-ui-menu.mjs.map +1 -1
  50. package/fesm2022/skra-ui-multi-select.mjs +102 -98
  51. package/fesm2022/skra-ui-multi-select.mjs.map +1 -1
  52. package/fesm2022/skra-ui-native-select.mjs +35 -17
  53. package/fesm2022/skra-ui-native-select.mjs.map +1 -1
  54. package/fesm2022/skra-ui-popover.mjs +5 -4
  55. package/fesm2022/skra-ui-popover.mjs.map +1 -1
  56. package/fesm2022/skra-ui-progress.mjs +7 -5
  57. package/fesm2022/skra-ui-progress.mjs.map +1 -1
  58. package/fesm2022/skra-ui-radio.mjs +3 -3
  59. package/fesm2022/skra-ui-radio.mjs.map +1 -1
  60. package/fesm2022/skra-ui-rating-display.mjs +14 -9
  61. package/fesm2022/skra-ui-rating-display.mjs.map +1 -1
  62. package/fesm2022/skra-ui-select.mjs +98 -95
  63. package/fesm2022/skra-ui-select.mjs.map +1 -1
  64. package/fesm2022/skra-ui-skeleton.mjs +16 -13
  65. package/fesm2022/skra-ui-skeleton.mjs.map +1 -1
  66. package/fesm2022/skra-ui-star-rating.mjs +18 -11
  67. package/fesm2022/skra-ui-star-rating.mjs.map +1 -1
  68. package/fesm2022/skra-ui-status-dot.mjs +7 -5
  69. package/fesm2022/skra-ui-status-dot.mjs.map +1 -1
  70. package/fesm2022/skra-ui-switch.mjs +3 -3
  71. package/fesm2022/skra-ui-switch.mjs.map +1 -1
  72. package/fesm2022/skra-ui-tabs.mjs +43 -29
  73. package/fesm2022/skra-ui-tabs.mjs.map +1 -1
  74. package/fesm2022/skra-ui-textarea.mjs +41 -15
  75. package/fesm2022/skra-ui-textarea.mjs.map +1 -1
  76. package/fesm2022/skra-ui-toast.mjs +35 -23
  77. package/fesm2022/skra-ui-toast.mjs.map +1 -1
  78. package/fesm2022/skra-ui-tooltip.mjs +12 -9
  79. package/fesm2022/skra-ui-tooltip.mjs.map +1 -1
  80. package/fesm2022/skra-ui-typography.mjs +9 -6
  81. package/fesm2022/skra-ui-typography.mjs.map +1 -1
  82. package/package.json +5 -5
  83. package/types/skra-ui-input.d.ts +24 -1
  84. package/types/skra-ui-input.d.ts.map +1 -1
  85. package/types/skra-ui-native-select.d.ts +9 -1
  86. package/types/skra-ui-native-select.d.ts.map +1 -1
  87. package/types/skra-ui-textarea.d.ts +10 -1
  88. package/types/skra-ui-textarea.d.ts.map +1 -1
@@ -67,10 +67,10 @@ class SkraSwitch {
67
67
  event.preventDefault();
68
68
  }
69
69
  }
70
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
71
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.7", type: SkraSwitch, isStandalone: true, selector: "input[type=\"checkbox\"][skraSwitch]", host: { attributes: { "role": "switch" }, listeners: { "click": "blockWhenReadonly($event)", "keydown": "blockKeyWhenReadonly($event)" }, properties: { "attr.data-skra-disabled": "context?.isDisabled() ? \"\" : null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-readonly": "context?.isReadonly() ? \"true\" : null", "attr.aria-describedby": "context?.describedByIds() ?? null" } }, ngImport: i0, template: '', isInline: true, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-background-readonly);border-color:var(--skra-comp-field-border-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
70
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
71
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraSwitch, isStandalone: true, selector: "input[type=\"checkbox\"][skraSwitch]", host: { attributes: { "role": "switch" }, listeners: { "click": "blockWhenReadonly($event)", "keydown": "blockKeyWhenReadonly($event)" }, properties: { "attr.data-skra-disabled": "context?.isDisabled() ? \"\" : null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-readonly": "context?.isReadonly() ? \"true\" : null", "attr.aria-describedby": "context?.describedByIds() ?? null" } }, ngImport: i0, template: '', isInline: true, styles: [":host{appearance:none;box-sizing:border-box;flex-shrink:0;cursor:pointer;outline:none;inline-size:var(--skra-comp-field-switch-track-inline-size);block-size:var(--skra-comp-field-switch-track-block-size);border-width:var(--skra-comp-field-switch-border-width);border-style:solid;border-color:var(--skra-comp-field-switch-border-color);border-radius:var(--skra-comp-field-switch-track-radius);background-color:var(--skra-comp-field-switch-background);--_switch-thumb: var(--skra-comp-field-switch-thumb-color);background-repeat:no-repeat;background-size:var(--skra-comp-field-switch-thumb-size) var(--skra-comp-field-switch-thumb-size);background-position:left var(--skra-comp-field-switch-thumb-inset) center;background-image:radial-gradient(circle,var(--_switch-thumb) 49%,transparent 50%);transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),background-position var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:checked){--_switch-thumb: var(--skra-comp-field-switch-thumb-color-checked);background-color:var(--skra-comp-field-switch-checked-background);border-color:var(--skra-comp-field-switch-checked-background);background-position:right var(--skra-comp-field-switch-thumb-inset) center}:host(:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-background-hover);border-color:var(--skra-comp-field-switch-border-color-hover)}:host(:checked:hover:not(:disabled):not([aria-readonly=true])){background-color:var(--skra-comp-field-switch-checked-background-hover);border-color:var(--skra-comp-field-switch-checked-background-hover)}:host(:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled),:host([data-skra-disabled]){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([aria-readonly=true]){cursor:default;background-color:var(--skra-comp-field-background-readonly);border-color:var(--skra-comp-field-border-color-readonly)}:host(:checked[aria-readonly=true]){background-color:var(--skra-comp-field-switch-checked-background-readonly);border-color:var(--skra-comp-field-switch-checked-background-readonly)}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
72
72
  }
73
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraSwitch, decorators: [{
73
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSwitch, decorators: [{
74
74
  type: Component,
75
75
  args: [{ selector: 'input[type="checkbox"][skraSwitch]', standalone: true, template: '', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
76
76
  // The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-switch.mjs","sources":["../../../../libs/ui/switch/src/lib/switch/switch.ts","../../../../libs/ui/switch/src/skra-ui-switch.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n effect,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * Wires a native `<input type=\"checkbox\">` to the **switch** role + skin when inside\n * `<skra-field>` (ADR 013), or standalone with no cascade. Per ADR 039/040, Forge ships\n * no `<skra-switch>` wrapper — this is a Component-on-the-native-host (`<input>` is void →\n * `template: ''`, ADR 040 §2) carrying its own `switch.scss` via Emulated encapsulation. The\n * ADR 039 revision history named this exact pattern as the future switch primitive.\n *\n * **The directive SETS `role=\"switch\"`** (it is not part of the selector) — the consumer must\n * not be asked to repeat an obvious, required ARIA role. No native HTML element produces switch\n * semantics, so `role=\"switch\"` is the legitimate ARIA mechanism (native-attr-first rule 2). The\n * browser maps the native checked state to `aria-checked` (on/off) under this role.\n *\n * <!-- inside Field -->\n * <skra-field>\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\n * <label skraLabelFor>Enable notifications</label>\n * </skra-field>\n *\n * <!-- standalone (label wraps input — no id/for needed) -->\n * <label>\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\n * Dark mode\n * </label>\n *\n * Value channel stays consumer-owned per ADR 037 (native `[checked]` + `(change)`, Reactive\n * Forms `formControlName`, Signal Forms `[formField]`, or `[(ngModel)]` — all orthogonal). Toggle\n * state is NOT reflected as `data-skra-*` (that would require Forge to observe native state,\n * violating ADR 037); the skin keys off the native `:checked` pseudo-class.\n *\n * Distinct from `skraCheckbox` (the atom-granularity split): a switch is strictly binary —\n * `role=\"switch\"` forbids `aria-checked=\"mixed\"`, so there is **no `indeterminate` input**.\n */\n@Component({\n selector: 'input[type=\"checkbox\"][skraSwitch]',\n standalone: true,\n // Void host — no <ng-content>. See ADR 040 §2.\n template: '',\n styleUrl: './switch.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).\n role: 'switch',\n '[attr.data-skra-disabled]': 'context?.isDisabled() ? \"\" : null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n // Readonly is ARIA-only (native `readonly` doesn't apply to checkboxes per HTML spec);\n // styling keys off `[aria-readonly]`. Mirrors skraCheckbox / skraRadio.\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '(click)': 'blockWhenReadonly($event)',\n '(keydown)': 'blockKeyWhenReadonly($event)',\n },\n})\nexport class SkraSwitch {\n private readonly el = inject<ElementRef<HTMLInputElement>>(ElementRef);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n constructor() {\n // Field-cascaded native properties — only bind when context is present so\n // standalone consumers retain full control of their static attributes.\n if (this.context) {\n const ctx = this.context;\n const el = this.el.nativeElement;\n effect(() => {\n el.id = ctx.fieldId();\n });\n effect(() => {\n el.disabled = ctx.isDisabled();\n });\n }\n }\n\n /**\n * Readonly enforcement — native checkbox has no `[readonly]`, so without this the\n * `aria-readonly` we announce would be a lie (the user could still toggle it).\n * `preventDefault` on `click` blocks the toggle from both pointer and Space (keyboard\n * activation dispatches a click on form controls). Mirrors the checkbox/radio guards.\n */\n protected blockWhenReadonly(event: Event): void {\n if (this.context?.isReadonly()) event.preventDefault();\n }\n\n /** Block keyboard activation (Space) when readonly; let `Tab` through. */\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\n if (this.context?.isReadonly() && event.key !== 'Tab') {\n event.preventDefault();\n }\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,UAAU,CAAA;AACJ,IAAA,EAAE,GAAG,MAAM,CAA+B,UAAU,CAAC;IAC7D,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;;;AAGE,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;AACxB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;YAChC,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;;;;AAKG;AACO,IAAA,iBAAiB,CAAC,KAAY,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE;IACxD;;AAGU,IAAA,oBAAoB,CAAC,KAAoB,EAAA;AACjD,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;YACrD,KAAK,CAAC,cAAc,EAAE;QACxB;IACF;uGAlCW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,2fAjBX,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,UAAU,EAAA,UAAA,EAAA,CAAA;kBArBtB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,EAAA,UAAA,EAClC,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,2BAA2B,EAAE,mCAAmC;AAChE,wBAAA,qBAAqB,EAAE,qCAAqC;;;AAG5D,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,SAAS,EAAE,2BAA2B;AACtC,wBAAA,WAAW,EAAE,8BAA8B;AAC5C,qBAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-switch.mjs","sources":["../../../../libs/ui/switch/src/lib/switch/switch.ts","../../../../libs/ui/switch/src/skra-ui-switch.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n effect,\r\n inject,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '@skra/ui/field';\r\n\r\n/**\r\n * Wires a native `<input type=\"checkbox\">` to the **switch** role + skin when inside\r\n * `<skra-field>` (ADR 013), or standalone with no cascade. Per ADR 039/040, Forge ships\r\n * no `<skra-switch>` wrapper — this is a Component-on-the-native-host (`<input>` is void →\r\n * `template: ''`, ADR 040 §2) carrying its own `switch.scss` via Emulated encapsulation. The\r\n * ADR 039 revision history named this exact pattern as the future switch primitive.\r\n *\r\n * **The directive SETS `role=\"switch\"`** (it is not part of the selector) — the consumer must\r\n * not be asked to repeat an obvious, required ARIA role. No native HTML element produces switch\r\n * semantics, so `role=\"switch\"` is the legitimate ARIA mechanism (native-attr-first rule 2). The\r\n * browser maps the native checked state to `aria-checked` (on/off) under this role.\r\n *\r\n * <!-- inside Field -->\r\n * <skra-field>\r\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\r\n * <label skraLabelFor>Enable notifications</label>\r\n * </skra-field>\r\n *\r\n * <!-- standalone (label wraps input — no id/for needed) -->\r\n * <label>\r\n * <input type=\"checkbox\" skraSwitch [checked]=\"x()\" (change)=\"x.set($any($event.target).checked)\" />\r\n * Dark mode\r\n * </label>\r\n *\r\n * Value channel stays consumer-owned per ADR 037 (native `[checked]` + `(change)`, Reactive\r\n * Forms `formControlName`, Signal Forms `[formField]`, or `[(ngModel)]` — all orthogonal). Toggle\r\n * state is NOT reflected as `data-skra-*` (that would require Forge to observe native state,\r\n * violating ADR 037); the skin keys off the native `:checked` pseudo-class.\r\n *\r\n * Distinct from `skraCheckbox` (the atom-granularity split): a switch is strictly binary —\r\n * `role=\"switch\"` forbids `aria-checked=\"mixed\"`, so there is **no `indeterminate` input**.\r\n */\r\n@Component({\r\n selector: 'input[type=\"checkbox\"][skraSwitch]',\r\n standalone: true,\r\n // Void host — no <ng-content>. See ADR 040 §2.\r\n template: '',\r\n styleUrl: './switch.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // The directive owns the switch semantic (resolved in scope, refines the ADR 039 sketch).\r\n role: 'switch',\r\n '[attr.data-skra-disabled]': 'context?.isDisabled() ? \"\" : null',\r\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\r\n // Readonly is ARIA-only (native `readonly` doesn't apply to checkboxes per HTML spec);\r\n // styling keys off `[aria-readonly]`. Mirrors skraCheckbox / skraRadio.\r\n '[attr.aria-readonly]': 'context?.isReadonly() ? \"true\" : null',\r\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\r\n '(click)': 'blockWhenReadonly($event)',\r\n '(keydown)': 'blockKeyWhenReadonly($event)',\r\n },\r\n})\r\nexport class SkraSwitch {\r\n private readonly el = inject<ElementRef<HTMLInputElement>>(ElementRef);\r\n readonly context = inject(SkraFieldContext, { optional: true });\r\n\r\n constructor() {\r\n // Field-cascaded native properties — only bind when context is present so\r\n // standalone consumers retain full control of their static attributes.\r\n if (this.context) {\r\n const ctx = this.context;\r\n const el = this.el.nativeElement;\r\n effect(() => {\r\n el.id = ctx.fieldId();\r\n });\r\n effect(() => {\r\n el.disabled = ctx.isDisabled();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Readonly enforcement — native checkbox has no `[readonly]`, so without this the\r\n * `aria-readonly` we announce would be a lie (the user could still toggle it).\r\n * `preventDefault` on `click` blocks the toggle from both pointer and Space (keyboard\r\n * activation dispatches a click on form controls). Mirrors the checkbox/radio guards.\r\n */\r\n protected blockWhenReadonly(event: Event): void {\r\n if (this.context?.isReadonly()) event.preventDefault();\r\n }\r\n\r\n /** Block keyboard activation (Space) when readonly; let `Tab` through. */\r\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\r\n if (this.context?.isReadonly() && event.key !== 'Tab') {\r\n event.preventDefault();\r\n }\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;MAsBU,UAAU,CAAA;AACJ,IAAA,EAAE,GAAG,MAAM,CAA+B,UAAU,CAAC;IAC7D,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;;;AAGE,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;AACxB,YAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;YAChC,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;;;;AAKG;AACO,IAAA,iBAAiB,CAAC,KAAY,EAAA;AACtC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE;YAAE,KAAK,CAAC,cAAc,EAAE;IACxD;;AAGU,IAAA,oBAAoB,CAAC,KAAoB,EAAA;AACjD,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE,UAAU,EAAE,IAAI,KAAK,CAAC,GAAG,KAAK,KAAK,EAAE;YACrD,KAAK,CAAC,cAAc,EAAE;QACxB;IACF;uGAlCW,UAAU,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAV,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAU,2fAjBX,EAAE,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAiBD,UAAU,EAAA,UAAA,EAAA,CAAA;kBArBtB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,EAAA,UAAA,EAClC,IAAI,EAAA,QAAA,EAEN,EAAE,EAAA,eAAA,EAEK,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,IAAI,EAAE,QAAQ;AACd,wBAAA,2BAA2B,EAAE,mCAAmC;AAChE,wBAAA,qBAAqB,EAAE,qCAAqC;;;AAG5D,wBAAA,sBAAsB,EAAE,uCAAuC;AAC/D,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,SAAS,EAAE,2BAA2B;AACtC,wBAAA,WAAW,EAAE,8BAA8B;AAC5C,qBAAA,EAAA,MAAA,EAAA,CAAA,qnFAAA,CAAA,EAAA;;;AC7DH;;AAEG;;;;"}
@@ -22,11 +22,14 @@ class SkraTabsContext {
22
22
  /** Unique per `[skraTabs]` — the prefix for every tab/panel id in this group. */
23
23
  baseId = `skra-tabs-${++tabsInstanceCounter}`;
24
24
  /** Mirror of the consumer's `[selected]` — drives `aria-selected` + panel visibility (read-only to children). */
25
- selected = signal('', ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
25
+ selected = signal('', /* @ts-ignore */
26
+ ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
26
27
  /** Roving-focus position — the value of the tab that currently carries `tabindex="0"` (read-only to children). */
27
- activeValue = signal('', ...(ngDevMode ? [{ debugName: "activeValue" }] : /* istanbul ignore next */ []));
28
+ activeValue = signal('', /* @ts-ignore */
29
+ ...(ngDevMode ? [{ debugName: "activeValue" }] : /* istanbul ignore next */ []));
28
30
  /** Activation model (read-only to children). */
29
- activation = signal('automatic', ...(ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []));
31
+ activation = signal('automatic', /* @ts-ignore */
32
+ ...(ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []));
30
33
  tabId(value) {
31
34
  return `${this.baseId}-tab-${idSafe(value)}`;
32
35
  }
@@ -40,10 +43,10 @@ class SkraTabsContext {
40
43
  select = () => undefined;
41
44
  /** Coordinator-assigned: the tablist forwards its `keydown` here (routed to the keyboard controller). */
42
45
  handleKeydown = () => undefined;
43
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabsContext, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
44
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabsContext });
46
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabsContext, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
47
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabsContext });
45
48
  }
46
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabsContext, decorators: [{
49
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabsContext, decorators: [{
47
50
  type: Injectable
48
51
  }] });
49
52
 
@@ -63,17 +66,22 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
63
66
  */
64
67
  class SkraTab {
65
68
  /** Selection key — matched against `skraTabs [selected]` and the owning panel's `value`. */
66
- value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
69
+ value = input.required(/* @ts-ignore */
70
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
67
71
  host = inject(ElementRef);
68
72
  ctx = inject(SkraTabsContext, { optional: true });
69
- tabId = computed(() => this.ctx?.tabId(this.value()) ?? null, ...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
70
- panelId = computed(() => this.ctx?.panelId(this.value()) ?? null, ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
71
- ariaSelected = computed(() => this.ctx?.isSelected(this.value()) ? 'true' : 'false', ...(ngDevMode ? [{ debugName: "ariaSelected" }] : /* istanbul ignore next */ []));
73
+ tabId = computed(() => this.ctx?.tabId(this.value()) ?? null, /* @ts-ignore */
74
+ ...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
75
+ panelId = computed(() => this.ctx?.panelId(this.value()) ?? null, /* @ts-ignore */
76
+ ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
77
+ ariaSelected = computed(() => this.ctx?.isSelected(this.value()) ? 'true' : 'false', /* @ts-ignore */
78
+ ...(ngDevMode ? [{ debugName: "ariaSelected" }] : /* istanbul ignore next */ []));
72
79
  tabindex = computed(() => {
73
80
  if (!this.ctx)
74
81
  return null; // standalone misuse — leave the native button focusable
75
82
  return this.ctx.activeValue() === this.value() ? '0' : '-1';
76
- }, ...(ngDevMode ? [{ debugName: "tabindex" }] : /* istanbul ignore next */ []));
83
+ }, /* @ts-ignore */
84
+ ...(ngDevMode ? [{ debugName: "tabindex" }] : /* istanbul ignore next */ []));
77
85
  constructor() {
78
86
  if (typeof ngDevMode === 'undefined' || ngDevMode) {
79
87
  if (!this.ctx) {
@@ -98,10 +106,10 @@ class SkraTab {
98
106
  return; // belt-and-suspenders (native disabled won't fire click)
99
107
  this.ctx?.select(this.value());
100
108
  }
101
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
102
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: SkraTab, isStandalone: true, selector: "button[skraTab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tab", "type": "button" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "tabId()", "attr.aria-controls": "panelId()", "attr.aria-selected": "ariaSelected()", "attr.tabindex": "tabindex()" } }, exportAs: ["skraTab"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
109
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTab, deps: [], target: i0.ɵɵFactoryTarget.Component });
110
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraTab, isStandalone: true, selector: "button[skraTab]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tab", "type": "button" }, listeners: { "click": "onClick()" }, properties: { "attr.id": "tabId()", "attr.aria-controls": "panelId()", "attr.aria-selected": "ariaSelected()", "attr.tabindex": "tabindex()" } }, exportAs: ["skraTab"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:inline-flex;align-items:center;justify-content:center;gap:var(--skra-comp-tabs-gap);position:relative;margin:0;box-sizing:border-box;appearance:none;cursor:pointer;background:var(--skra-comp-tabs-background);color:var(--skra-comp-tabs-foreground);border-color:var(--skra-comp-tabs-border-color);border-width:var(--skra-comp-tabs-border-width);border-style:var(--skra-comp-tabs-border-style);border-radius:var(--skra-comp-tabs-radius);padding-block:var(--skra-comp-tabs-padding-block);padding-inline:var(--skra-comp-tabs-padding-inline);box-shadow:var(--skra-comp-tabs-shadow);font-family:var(--skra-sys-typography-role-label-large-font-family);font-size:var(--skra-sys-typography-role-label-large-font-size);font-weight:var(--skra-sys-typography-role-label-large-font-weight);line-height:var(--skra-sys-typography-role-label-large-line-height);letter-spacing:var(--skra-sys-typography-role-label-large-letter-spacing);transition:color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing),background-color var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host:after{content:\"\";position:absolute;inset-inline:0;inset-block-end:calc(-1 * var(--skra-comp-tabs-tablist-border-width));block-size:var(--skra-comp-tabs-indicator-thickness);background-color:var(--skra-comp-tabs-indicator-color);opacity:0;transition:opacity var(--skra-comp-tabs-motion-duration) var(--skra-comp-tabs-motion-easing)}:host(:hover:not(:disabled)){background-color:var(--skra-comp-tabs-background-hover);color:var(--skra-comp-tabs-foreground-selected)}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}:host([aria-selected=true]){color:var(--skra-comp-tabs-foreground-selected)}:host([aria-selected=true]):after{opacity:1}:host(:disabled){color:var(--skra-comp-tabs-foreground-disabled);cursor:default}@media(prefers-reduced-motion:reduce){:host,:host:after{transition-duration:0ms}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
103
111
  }
104
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTab, decorators: [{
112
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTab, decorators: [{
105
113
  type: Component,
106
114
  args: [{ selector: 'button[skraTab]', standalone: true, exportAs: 'skraTab', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
107
115
  role: 'tab',
@@ -123,12 +131,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
123
131
  */
124
132
  class SkraTabPanel {
125
133
  /** Selection key — matched against the owning `button[skraTab]`'s `value`. */
126
- value = input.required(...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
134
+ value = input.required(/* @ts-ignore */
135
+ ...(ngDevMode ? [{ debugName: "value" }] : /* istanbul ignore next */ []));
127
136
  ctx = inject(SkraTabsContext, { optional: true });
128
- panelId = computed(() => this.ctx?.panelId(this.value()) ?? null, ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
129
- tabId = computed(() => this.ctx?.tabId(this.value()) ?? null, ...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
137
+ panelId = computed(() => this.ctx?.panelId(this.value()) ?? null, /* @ts-ignore */
138
+ ...(ngDevMode ? [{ debugName: "panelId" }] : /* istanbul ignore next */ []));
139
+ tabId = computed(() => this.ctx?.tabId(this.value()) ?? null, /* @ts-ignore */
140
+ ...(ngDevMode ? [{ debugName: "tabId" }] : /* istanbul ignore next */ []));
130
141
  /** `''` (attribute present) when not selected → hidden; `null` (absent) when selected → shown. */
131
- hidden = computed(() => this.ctx?.isSelected(this.value()) ? null : '', ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
142
+ hidden = computed(() => this.ctx?.isSelected(this.value()) ? null : '', /* @ts-ignore */
143
+ ...(ngDevMode ? [{ debugName: "hidden" }] : /* istanbul ignore next */ []));
132
144
  constructor() {
133
145
  if (typeof ngDevMode === 'undefined' || ngDevMode) {
134
146
  if (!this.ctx) {
@@ -137,10 +149,10 @@ class SkraTabPanel {
137
149
  }
138
150
  }
139
151
  }
140
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
141
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.7", type: SkraTabPanel, isStandalone: true, selector: "[skraTabPanel]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tabpanel", "tabindex": "0" }, properties: { "attr.id": "panelId()", "attr.aria-labelledby": "tabId()", "attr.hidden": "hidden()" } }, exportAs: ["skraTabPanel"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:block;margin:0;box-sizing:border-box;padding-block:var(--skra-comp-tabs-panel-padding-block);padding-inline:var(--skra-comp-tabs-panel-padding-inline)}:host([hidden]){display:none}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
152
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabPanel, deps: [], target: i0.ɵɵFactoryTarget.Component });
153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraTabPanel, isStandalone: true, selector: "[skraTabPanel]", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: true, transformFunction: null } }, host: { attributes: { "role": "tabpanel", "tabindex": "0" }, properties: { "attr.id": "panelId()", "attr.aria-labelledby": "tabId()", "attr.hidden": "hidden()" } }, exportAs: ["skraTabPanel"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:block;margin:0;box-sizing:border-box;padding-block:var(--skra-comp-tabs-panel-padding-block);padding-inline:var(--skra-comp-tabs-panel-padding-inline)}:host([hidden]){display:none}:host(:focus-visible){outline:var(--skra-comp-tabs-focus-ring-width) solid var(--skra-comp-tabs-focus-ring-color);outline-offset:calc(-1 * var(--skra-comp-tabs-focus-ring-width))}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
142
154
  }
143
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabPanel, decorators: [{
155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabPanel, decorators: [{
144
156
  type: Component,
145
157
  args: [{ selector: '[skraTabPanel]', standalone: true, exportAs: 'skraTabPanel', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
146
158
  role: 'tabpanel',
@@ -232,9 +244,11 @@ class SkraTabsKeyboard {
232
244
  */
233
245
  class SkraTabs {
234
246
  /** Consumer-owned selection key (matches a tab's `value`); '' / no-match → nothing selected (ADR 037). */
235
- selected = input('', ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
247
+ selected = input('', /* @ts-ignore */
248
+ ...(ngDevMode ? [{ debugName: "selected" }] : /* istanbul ignore next */ []));
236
249
  /** Automatic (selection follows roving focus) | manual (Enter/Space selects). */
237
- activation = input('automatic', ...(ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []));
250
+ activation = input('automatic', /* @ts-ignore */
251
+ ...(ngDevMode ? [{ debugName: "activation" }] : /* istanbul ignore next */ []));
238
252
  /** Fires ONLY on user activation — never on a programmatic `[selected]` change. */
239
253
  selectedChange = output();
240
254
  ctx = inject(SkraTabsContext);
@@ -302,10 +316,10 @@ class SkraTabs {
302
316
  console.warn(`[skraTabs] panel value="${v}" has no matching button[skraTab] — it will never be revealed.`);
303
317
  }
304
318
  }
305
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabs, deps: [], target: i0.ɵɵFactoryTarget.Directive });
306
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "21.2.7", type: SkraTabs, isStandalone: true, selector: "[skraTabs]", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, activation: { classPropertyName: "activation", publicName: "activation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange" }, providers: [SkraTabsContext], queries: [{ propertyName: "tabs", predicate: SkraTab, descendants: true, isSignal: true }, { propertyName: "panels", predicate: SkraTabPanel, descendants: true, isSignal: true }], exportAs: ["skraTabs"], ngImport: i0 });
319
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabs, deps: [], target: i0.ɵɵFactoryTarget.Directive });
320
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "22.1.1", type: SkraTabs, isStandalone: true, selector: "[skraTabs]", inputs: { selected: { classPropertyName: "selected", publicName: "selected", isSignal: true, isRequired: false, transformFunction: null }, activation: { classPropertyName: "activation", publicName: "activation", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { selectedChange: "selectedChange" }, providers: [SkraTabsContext], queries: [{ propertyName: "tabs", predicate: SkraTab, descendants: true, isSignal: true }, { propertyName: "panels", predicate: SkraTabPanel, descendants: true, isSignal: true }], exportAs: ["skraTabs"], ngImport: i0 });
307
321
  }
308
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTabs, decorators: [{
322
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTabs, decorators: [{
309
323
  type: Directive,
310
324
  args: [{
311
325
  selector: '[skraTabs]',
@@ -336,10 +350,10 @@ class SkraTablist {
336
350
  onKeydown(event) {
337
351
  this.ctx?.handleKeydown(event);
338
352
  }
339
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTablist, deps: [], target: i0.ɵɵFactoryTarget.Component });
340
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.7", type: SkraTablist, isStandalone: true, selector: "[skraTablist]", host: { attributes: { "role": "tablist", "aria-orientation": "horizontal" }, listeners: { "keydown": "onKeydown($event)" } }, exportAs: ["skraTablist"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;gap:var(--skra-comp-tabs-gap);margin:0;box-sizing:border-box;border-block-end:var(--skra-comp-tabs-tablist-border-width) solid var(--skra-comp-tabs-tablist-border-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
353
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTablist, deps: [], target: i0.ɵɵFactoryTarget.Component });
354
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraTablist, isStandalone: true, selector: "[skraTablist]", host: { attributes: { "role": "tablist", "aria-orientation": "horizontal" }, listeners: { "keydown": "onKeydown($event)" } }, exportAs: ["skraTablist"], ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: ["@charset \"UTF-8\";:host{display:flex;align-items:stretch;gap:var(--skra-comp-tabs-gap);margin:0;box-sizing:border-box;border-block-end:var(--skra-comp-tabs-tablist-border-width) solid var(--skra-comp-tabs-tablist-border-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
341
355
  }
342
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTablist, decorators: [{
356
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTablist, decorators: [{
343
357
  type: Component,
344
358
  args: [{ selector: '[skraTablist]', standalone: true, exportAs: 'skraTablist', template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
345
359
  role: 'tablist',
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-tabs.mjs","sources":["../../../../libs/ui/tabs/src/lib/tabs/tabs-context.ts","../../../../libs/ui/tabs/src/lib/tabs/tab.ts","../../../../libs/ui/tabs/src/lib/tabs/tab-panel.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs-keyboard.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs.ts","../../../../libs/ui/tabs/src/lib/tabs/tablist.ts","../../../../libs/ui/tabs/src/skra-ui-tabs.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\n\n/** Module-global counter → a deterministic, unique id base per `[skraTabs]` instance.\n * Equivalent to the forms `IdGeneratorService` (ADR 013) but lib-local, so `@skra/navigation`\n * takes no dependency on `@skra/forms` just for id generation. Stable across SSR↔hydration\n * (same instantiation order yields the same ids — the standard counter technique). */\nlet tabsInstanceCounter = 0;\n\n/** Sanitize a consumer `value` into an id-safe fragment (no spaces / special chars). */\nfunction idSafe(value: string): string {\n return value.replace(/[^a-zA-Z0-9_-]/g, '-');\n}\n\n/**\n * DI Context provided per `[skraTabs]` instance — the ADR 013 §3.6 **non-form** Contextual-ID-Sync\n * bus wiring `tab` ↔ `tabpanel`. It carries **IDs + derived, read-only interaction state only**\n * (`selected` mirrors the consumer's `[selected]`; `activeValue` is the roving-focus position). It\n * **never owns value** — selection stays consumer-owned (ADR 037); a tab requests a change through\n * `select()`, which the coordinator implements and from which it emits `(selectedChange)`.\n */\n@Injectable()\nexport class SkraTabsContext {\n /** Unique per `[skraTabs]` — the prefix for every tab/panel id in this group. */\n private readonly baseId = `skra-tabs-${++tabsInstanceCounter}`;\n\n /** Mirror of the consumer's `[selected]` — drives `aria-selected` + panel visibility (read-only to children). */\n readonly selected = signal<string>('');\n /** Roving-focus position — the value of the tab that currently carries `tabindex=\"0\"` (read-only to children). */\n readonly activeValue = signal<string>('');\n /** Activation model (read-only to children). */\n readonly activation = signal<'automatic' | 'manual'>('automatic');\n\n tabId(value: string): string {\n return `${this.baseId}-tab-${idSafe(value)}`;\n }\n panelId(value: string): string {\n return `${this.baseId}-panel-${idSafe(value)}`;\n }\n isSelected(value: string): boolean {\n return this.selected() === value;\n }\n\n /** Coordinator-assigned: a tab/keyboard requests selection (the coordinator emits `(selectedChange)`). */\n select: (value: string) => void = () => undefined;\n /** Coordinator-assigned: the tablist forwards its `keydown` here (routed to the keyboard controller). */\n handleKeydown: (event: KeyboardEvent) => void = () => undefined;\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\n\nimport { SkraTabsContext } from './tabs-context';\nimport type { SkraTabKeyItem } from './tabs-types';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTab — a single tab, a Component on the native command host `button[skraTab]` (ADR 012/040:\n * a `<button>` gives Enter/Space→click + focusability for free; its implicit role is overridden to\n * `role=\"tab\"`, the precedent set by `button[skraMenuItem]`).\n *\n * Roving tabindex: `tabindex=\"0\"` only when this tab is the roving stop (`SkraTabsContext.activeValue`),\n * else `-1` — the controller (`SkraTabsKeyboard`) moves real focus. `aria-selected` reflects the\n * consumer-owned selection (`[selected]`), NOT the roving focus — and is the source of truth for the\n * selected STYLE too (CSS keys off `:host([aria-selected=\"true\"])`; no `data-skra-*`). On activation it\n * REQUESTS selection from the coordinator (`ctx.select`) — it never mutates selection itself (ADR 037).\n *\n * **Disabled is native-attr-first (boundary #9): the consumer sets the native `disabled` attribute** —\n * Forge OBSERVES it (no `disabled` input). A disabled tab is SKIPPED in the roving order (APG).\n */\n@Component({\n selector: 'button[skraTab]',\n standalone: true,\n exportAs: 'skraTab',\n template: '<ng-content></ng-content>',\n styleUrl: './tab.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tab',\n type: 'button', // never an implicit submit if the tablist sits inside a <form>\n '[attr.id]': 'tabId()',\n '[attr.aria-controls]': 'panelId()',\n '[attr.aria-selected]': 'ariaSelected()',\n '[attr.tabindex]': 'tabindex()',\n '(click)': 'onClick()',\n },\n})\nexport class SkraTab implements SkraTabKeyItem {\n /** Selection key — matched against `skraTabs [selected]` and the owning panel's `value`. */\n readonly value = input.required<string>();\n\n private readonly host = inject<ElementRef<HTMLButtonElement>>(ElementRef);\n private readonly ctx = inject(SkraTabsContext, { optional: true });\n\n protected readonly tabId = computed(\n () => this.ctx?.tabId(this.value()) ?? null,\n );\n protected readonly panelId = computed(\n () => this.ctx?.panelId(this.value()) ?? null,\n );\n protected readonly ariaSelected = computed(() =>\n this.ctx?.isSelected(this.value()) ? 'true' : 'false',\n );\n protected readonly tabindex = computed(() => {\n if (!this.ctx) return null; // standalone misuse — leave the native button focusable\n return this.ctx.activeValue() === this.value() ? '0' : '-1';\n });\n\n constructor() {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n if (!this.ctx) {\n console.warn(\n '[skraTab] has no [skraTabs] ancestor — it is not wired to a tablist (no aria-controls / ' +\n 'roving / selection). Project it inside <div skraTablist> within <element skraTabs>.',\n );\n }\n }\n }\n\n // ── SkraTabKeyItem (driven by SkraTabsKeyboard / CDK FocusKeyManager) ──\n focus(): void {\n this.host.nativeElement.focus();\n }\n /** Disabled tabs are skipped in the roving order — read live off the native attribute (no input). */\n isDisabled(): boolean {\n return this.host.nativeElement.disabled;\n }\n getValue(): string {\n return this.value();\n }\n\n protected onClick(): void {\n if (this.host.nativeElement.disabled) return; // belt-and-suspenders (native disabled won't fire click)\n this.ctx?.select(this.value());\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n computed,\n inject,\n input,\n} from '@angular/core';\n\nimport { SkraTabsContext } from './tabs-context';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTabPanel — the `role=\"tabpanel\"` for one tab, a Component on the consumer's `<div skraTabPanel>`\n * (ADR 040, `template: '<ng-content>'` so the panel body renders). It is focusable (`tabindex=\"0\"`, APG —\n * keyboard users Tab from the active tab into its content), auto-named by `aria-labelledby`→its tab, and\n * `hidden` when its `value` is not the selected one (removed from the a11y tree; stays in the DOM — lazy\n * mounting is the consumer's own `@if` on the content).\n */\n@Component({\n selector: '[skraTabPanel]',\n standalone: true,\n exportAs: 'skraTabPanel',\n template: '<ng-content></ng-content>',\n styleUrl: './tab-panel.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tabpanel',\n tabindex: '0',\n '[attr.id]': 'panelId()',\n '[attr.aria-labelledby]': 'tabId()',\n '[attr.hidden]': 'hidden()',\n },\n})\nexport class SkraTabPanel {\n /** Selection key — matched against the owning `button[skraTab]`'s `value`. */\n readonly value = input.required<string>();\n\n private readonly ctx = inject(SkraTabsContext, { optional: true });\n\n protected readonly panelId = computed(\n () => this.ctx?.panelId(this.value()) ?? null,\n );\n protected readonly tabId = computed(\n () => this.ctx?.tabId(this.value()) ?? null,\n );\n /** `''` (attribute present) when not selected → hidden; `null` (absent) when selected → shown. */\n protected readonly hidden = computed(() =>\n this.ctx?.isSelected(this.value()) ? null : '',\n );\n\n constructor() {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n if (!this.ctx) {\n console.warn(\n '[skraTabPanel] has no [skraTabs] ancestor — it cannot be linked to a tab or shown/hidden. ' +\n 'Project it inside <element skraTabs>.',\n );\n }\n }\n }\n}\n","import { FocusKeyManager } from '@angular/cdk/a11y';\n\nimport type { SkraTabKeyItem } from './tabs-types';\n\n/**\n * SkraTabsKeyboard — the WAI-ARIA APG **Tabs** roving-tabindex keyboard model, confined to ONE file.\n *\n * This is the **only** module in `@skra/navigation` that imports `@angular/cdk` (ADR 0044 §7,\n * generalized library-wide 2026-06-19). It wraps CDK `FocusKeyManager` (roving REAL focus) so the\n * engine is swappable in one file — exactly as `SkraMenuKeyboard` does for the menu. Unlike the menu,\n * tabs use **horizontal** orientation (Left/Right) and **skip** disabled tabs.\n *\n * Owns: Left/Right roving (wrap), Home/End. Enter/Space (native button activation) and selection are\n * the coordinator's job — the controller only moves focus and reports the active tab's value.\n */\nexport class SkraTabsKeyboard {\n private manager?: FocusKeyManager<SkraTabKeyItem>;\n private items: SkraTabKeyItem[] = [];\n\n /**\n * (Re)build the manager from the current projected tab set. Called from an `effect` on the signal\n * `contentChildren` — a passed array is a static snapshot, so the manager is rebuilt whenever the\n * tab set changes (the documented signal↔CDK seam, mirroring `menu-keyboard.ts`).\n */\n setItems(items: readonly SkraTabKeyItem[]): void {\n this.items = [...items];\n this.manager?.destroy();\n this.manager = new FocusKeyManager<SkraTabKeyItem>(this.items)\n .withHorizontalOrientation('ltr') // Left/Right; RTL handled by the manager via the page dir\n .withWrap()\n .withHomeAndEnd()\n // Tabs SKIP disabled (APG): a disabled tab is not a roving stop. (Menu keeps them focusable.)\n .skipPredicate((tab) => tab.isDisabled());\n }\n\n /** Delegate Left/Right/Home/End. Enter/Space/Tab are intentionally left to the platform/coordinator. */\n onKeydown(event: KeyboardEvent): void {\n this.manager?.onKeydown(event);\n }\n\n /** The value of the tab the manager currently considers active (focused after `onKeydown`). */\n activeValue(): string | undefined {\n return this.manager?.activeItem?.getValue();\n }\n\n /** Sync the manager's active index to a value WITHOUT moving focus (after a click / on init). */\n setActive(value: string): void {\n const index = this.items.findIndex((tab) => tab.getValue() === value);\n if (index >= 0) this.manager?.updateActiveItem(index);\n }\n\n /** The first non-disabled tab's value (the roving stop when nothing is selected) — APG. */\n firstEnabledValue(): string | undefined {\n return this.items.find((tab) => !tab.isDisabled())?.getValue();\n }\n\n hasValue(value: string): boolean {\n return this.items.some((tab) => tab.getValue() === value);\n }\n\n destroy(): void {\n this.manager?.destroy();\n this.manager = undefined;\n }\n}\n","import {\n DestroyRef,\n Directive,\n contentChildren,\n effect,\n inject,\n input,\n output,\n} from '@angular/core';\n\nimport { SkraTab } from './tab';\nimport { SkraTabPanel } from './tab-panel';\nimport { SkraTabsContext } from './tabs-context';\nimport { SkraTabsKeyboard } from './tabs-keyboard';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTabs — the WAI-ARIA APG **Tabs** coordinator. A directive on a wrapping element that holds a\n * `[skraTablist]` (the `role=\"tablist\"` with its `button[skraTab]` children) and the\n * `[skraTabPanel]` panels as DI descendants. It provides `SkraTabsContext` (the ADR 013 §3.6 non-form\n * Contextual-ID-Sync bus), owns the consumer-facing `[selected]` / `(selectedChange)` (controlled,\n * ADR 037 — NO internal selection state) and `[activation]`, and drives the roving-tabindex keyboard\n * (`SkraTabsKeyboard` → CDK `FocusKeyManager`).\n *\n * <div skraTabs [selected]=\"tab()\" (selectedChange)=\"tab.set($event)\">\n * <div skraTablist aria-label=\"Account\">\n * <button skraTab value=\"profile\">Profile</button>\n * <button skraTab value=\"security\">Security</button>\n * </div>\n * <div skraTabPanel value=\"profile\">…</div>\n * <div skraTabPanel value=\"security\">…</div>\n * </div>\n *\n * Selection is consumer-owned: a click / Enter / Space / (automatic) arrow emits `(selectedChange)`;\n * the visible selection updates when the consumer round-trips `[selected]`. The roving focus position\n * (`tabindex=\"0\"`) is component-owned UI state — it moves immediately, independent of `[selected]`.\n *\n * Full contract: adr/specs/component-tabs-spec.md.\n */\n@Directive({\n selector: '[skraTabs]',\n standalone: true,\n exportAs: 'skraTabs',\n providers: [SkraTabsContext],\n})\nexport class SkraTabs {\n /** Consumer-owned selection key (matches a tab's `value`); '' / no-match → nothing selected (ADR 037). */\n readonly selected = input<string>('');\n /** Automatic (selection follows roving focus) | manual (Enter/Space selects). */\n readonly activation = input<'automatic' | 'manual'>('automatic');\n /** Fires ONLY on user activation — never on a programmatic `[selected]` change. */\n readonly selectedChange = output<string>();\n\n private readonly ctx = inject(SkraTabsContext);\n private readonly tabs = contentChildren(SkraTab, { descendants: true });\n private readonly panels = contentChildren(SkraTabPanel, {\n descendants: true,\n });\n private readonly keyboard = new SkraTabsKeyboard();\n\n constructor() {\n // Wire the context bus (a tab requests selection; the tablist forwards keydown).\n this.ctx.select = (value) => this.selectTab(value);\n this.ctx.handleKeydown = (event) => this.onTablistKeydown(event);\n\n // Mirror inputs → context (read-only to children).\n effect(() => this.ctx.selected.set(this.selected()));\n effect(() => this.ctx.activation.set(this.activation()));\n\n // (Re)build the keyboard from the projected tab set and (re)seat the roving stop whenever the tab\n // set or the selection changes. Rebuilding the manager for a handful of tabs is trivial.\n effect(() => {\n this.keyboard.setItems(this.tabs());\n this.reseat();\n });\n\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n effect(() => this.warnMismatches());\n }\n\n inject(DestroyRef).onDestroy(() => this.keyboard.destroy());\n }\n\n /** Seat the roving stop (`tabindex=\"0\"`) on a real, enabled tab: the selected one if valid, else the\n * first enabled tab (APG — the tablist must always have exactly one tab stop). */\n private reseat(): void {\n const sel = this.selected();\n const next = this.keyboard.hasValue(sel)\n ? sel\n : (this.keyboard.firstEnabledValue() ?? '');\n this.ctx.activeValue.set(next);\n if (next) this.keyboard.setActive(next);\n }\n\n /** A tab was activated (click / Enter / Space / automatic arrow). Move the roving stop immediately\n * (UI state), then REQUEST selection from the consumer — never mutate selection internally (ADR 037). */\n private selectTab(value: string): void {\n this.ctx.activeValue.set(value);\n this.keyboard.setActive(value);\n if (this.selected() === value) return; // idempotent — no redundant output\n this.selectedChange.emit(value);\n }\n\n private onTablistKeydown(event: KeyboardEvent): void {\n const before = this.keyboard.activeValue();\n this.keyboard.onKeydown(event);\n const after = this.keyboard.activeValue();\n if (after && after !== before) {\n this.ctx.activeValue.set(after); // roving moved (focus already on the new tab)\n if (this.ctx.activation() === 'automatic') this.selectTab(after);\n }\n }\n\n /** Dev-only nudge: every tab needs a panel of the same `value`, and vice-versa (aria-controls / -labelledby). */\n private warnMismatches(): void {\n const tabValues = new Set(this.tabs().map((t) => t.value()));\n const panelValues = new Set(this.panels().map((p) => p.value()));\n for (const v of tabValues) {\n if (!panelValues.has(v))\n console.warn(\n `[skraTabs] tab value=\"${v}\" has no matching [skraTabPanel] — its aria-controls points to a missing panel.`,\n );\n }\n for (const v of panelValues) {\n if (!tabValues.has(v))\n console.warn(\n `[skraTabs] panel value=\"${v}\" has no matching button[skraTab] — it will never be revealed.`,\n );\n }\n }\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\n\nimport { SkraTabsContext } from './tabs-context';\n\ndeclare const ngDevMode: boolean | undefined;\n\n/**\n * SkraTablist — the `role=\"tablist\"` container, a Component on the consumer's `<div skraTablist>`\n * (ADR 040, `template: '<ng-content>'` so the projected `button[skraTab]` children render). It carries\n * the rail styling and forwards its `keydown` to the coordinator's roving keyboard (`SkraTabsKeyboard`)\n * via the `SkraTabsContext` bus. Name it for AT with consumer `aria-label`/`aria-labelledby` (ADR 033).\n */\n@Component({\n selector: '[skraTablist]',\n standalone: true,\n exportAs: 'skraTablist',\n template: '<ng-content></ng-content>',\n styleUrl: './tablist.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n role: 'tablist',\n 'aria-orientation': 'horizontal',\n '(keydown)': 'onKeydown($event)',\n },\n})\nexport class SkraTablist {\n private readonly ctx = inject(SkraTabsContext, { optional: true });\n\n constructor() {\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\n if (!this.ctx) {\n console.warn(\n '[skraTablist] has no [skraTabs] ancestor — its tabs cannot be keyboard-navigated. ' +\n 'Wrap the tablist + panels in <element skraTabs>.',\n );\n }\n }\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n this.ctx?.handleKeydown(event);\n }\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skra-ui-tabs.mjs","sources":["../../../../libs/ui/tabs/src/lib/tabs/tabs-context.ts","../../../../libs/ui/tabs/src/lib/tabs/tab.ts","../../../../libs/ui/tabs/src/lib/tabs/tab-panel.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs-keyboard.ts","../../../../libs/ui/tabs/src/lib/tabs/tabs.ts","../../../../libs/ui/tabs/src/lib/tabs/tablist.ts","../../../../libs/ui/tabs/src/skra-ui-tabs.ts"],"sourcesContent":["import { Injectable, signal } from '@angular/core';\r\n\r\n/** Module-global counter → a deterministic, unique id base per `[skraTabs]` instance.\r\n * Equivalent to the forms `IdGeneratorService` (ADR 013) but lib-local, so `@skra/navigation`\r\n * takes no dependency on `@skra/forms` just for id generation. Stable across SSR↔hydration\r\n * (same instantiation order yields the same ids — the standard counter technique). */\r\nlet tabsInstanceCounter = 0;\r\n\r\n/** Sanitize a consumer `value` into an id-safe fragment (no spaces / special chars). */\r\nfunction idSafe(value: string): string {\r\n return value.replace(/[^a-zA-Z0-9_-]/g, '-');\r\n}\r\n\r\n/**\r\n * DI Context provided per `[skraTabs]` instance — the ADR 013 §3.6 **non-form** Contextual-ID-Sync\r\n * bus wiring `tab` ↔ `tabpanel`. It carries **IDs + derived, read-only interaction state only**\r\n * (`selected` mirrors the consumer's `[selected]`; `activeValue` is the roving-focus position). It\r\n * **never owns value** — selection stays consumer-owned (ADR 037); a tab requests a change through\r\n * `select()`, which the coordinator implements and from which it emits `(selectedChange)`.\r\n */\r\n@Injectable()\r\nexport class SkraTabsContext {\r\n /** Unique per `[skraTabs]` — the prefix for every tab/panel id in this group. */\r\n private readonly baseId = `skra-tabs-${++tabsInstanceCounter}`;\r\n\r\n /** Mirror of the consumer's `[selected]` — drives `aria-selected` + panel visibility (read-only to children). */\r\n readonly selected = signal<string>('');\r\n /** Roving-focus position — the value of the tab that currently carries `tabindex=\"0\"` (read-only to children). */\r\n readonly activeValue = signal<string>('');\r\n /** Activation model (read-only to children). */\r\n readonly activation = signal<'automatic' | 'manual'>('automatic');\r\n\r\n tabId(value: string): string {\r\n return `${this.baseId}-tab-${idSafe(value)}`;\r\n }\r\n panelId(value: string): string {\r\n return `${this.baseId}-panel-${idSafe(value)}`;\r\n }\r\n isSelected(value: string): boolean {\r\n return this.selected() === value;\r\n }\r\n\r\n /** Coordinator-assigned: a tab/keyboard requests selection (the coordinator emits `(selectedChange)`). */\r\n select: (value: string) => void = () => undefined;\r\n /** Coordinator-assigned: the tablist forwards its `keydown` here (routed to the keyboard controller). */\r\n handleKeydown: (event: KeyboardEvent) => void = () => undefined;\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n computed,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport { SkraTabsContext } from './tabs-context';\r\nimport type { SkraTabKeyItem } from './tabs-types';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTab — a single tab, a Component on the native command host `button[skraTab]` (ADR 012/040:\r\n * a `<button>` gives Enter/Space→click + focusability for free; its implicit role is overridden to\r\n * `role=\"tab\"`, the precedent set by `button[skraMenuItem]`).\r\n *\r\n * Roving tabindex: `tabindex=\"0\"` only when this tab is the roving stop (`SkraTabsContext.activeValue`),\r\n * else `-1` — the controller (`SkraTabsKeyboard`) moves real focus. `aria-selected` reflects the\r\n * consumer-owned selection (`[selected]`), NOT the roving focus — and is the source of truth for the\r\n * selected STYLE too (CSS keys off `:host([aria-selected=\"true\"])`; no `data-skra-*`). On activation it\r\n * REQUESTS selection from the coordinator (`ctx.select`) — it never mutates selection itself (ADR 037).\r\n *\r\n * **Disabled is native-attr-first (boundary #9): the consumer sets the native `disabled` attribute** —\r\n * Forge OBSERVES it (no `disabled` input). A disabled tab is SKIPPED in the roving order (APG).\r\n */\r\n@Component({\r\n selector: 'button[skraTab]',\r\n standalone: true,\r\n exportAs: 'skraTab',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './tab.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tab',\r\n type: 'button', // never an implicit submit if the tablist sits inside a <form>\r\n '[attr.id]': 'tabId()',\r\n '[attr.aria-controls]': 'panelId()',\r\n '[attr.aria-selected]': 'ariaSelected()',\r\n '[attr.tabindex]': 'tabindex()',\r\n '(click)': 'onClick()',\r\n },\r\n})\r\nexport class SkraTab implements SkraTabKeyItem {\r\n /** Selection key — matched against `skraTabs [selected]` and the owning panel's `value`. */\r\n readonly value = input.required<string>();\r\n\r\n private readonly host = inject<ElementRef<HTMLButtonElement>>(ElementRef);\r\n private readonly ctx = inject(SkraTabsContext, { optional: true });\r\n\r\n protected readonly tabId = computed(\r\n () => this.ctx?.tabId(this.value()) ?? null,\r\n );\r\n protected readonly panelId = computed(\r\n () => this.ctx?.panelId(this.value()) ?? null,\r\n );\r\n protected readonly ariaSelected = computed(() =>\r\n this.ctx?.isSelected(this.value()) ? 'true' : 'false',\r\n );\r\n protected readonly tabindex = computed(() => {\r\n if (!this.ctx) return null; // standalone misuse — leave the native button focusable\r\n return this.ctx.activeValue() === this.value() ? '0' : '-1';\r\n });\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.ctx) {\r\n console.warn(\r\n '[skraTab] has no [skraTabs] ancestor — it is not wired to a tablist (no aria-controls / ' +\r\n 'roving / selection). Project it inside <div skraTablist> within <element skraTabs>.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n // ── SkraTabKeyItem (driven by SkraTabsKeyboard / CDK FocusKeyManager) ──\r\n focus(): void {\r\n this.host.nativeElement.focus();\r\n }\r\n /** Disabled tabs are skipped in the roving order — read live off the native attribute (no input). */\r\n isDisabled(): boolean {\r\n return this.host.nativeElement.disabled;\r\n }\r\n getValue(): string {\r\n return this.value();\r\n }\r\n\r\n protected onClick(): void {\r\n if (this.host.nativeElement.disabled) return; // belt-and-suspenders (native disabled won't fire click)\r\n this.ctx?.select(this.value());\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n computed,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\n\r\nimport { SkraTabsContext } from './tabs-context';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTabPanel — the `role=\"tabpanel\"` for one tab, a Component on the consumer's `<div skraTabPanel>`\r\n * (ADR 040, `template: '<ng-content>'` so the panel body renders). It is focusable (`tabindex=\"0\"`, APG —\r\n * keyboard users Tab from the active tab into its content), auto-named by `aria-labelledby`→its tab, and\r\n * `hidden` when its `value` is not the selected one (removed from the a11y tree; stays in the DOM — lazy\r\n * mounting is the consumer's own `@if` on the content).\r\n */\r\n@Component({\r\n selector: '[skraTabPanel]',\r\n standalone: true,\r\n exportAs: 'skraTabPanel',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './tab-panel.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tabpanel',\r\n tabindex: '0',\r\n '[attr.id]': 'panelId()',\r\n '[attr.aria-labelledby]': 'tabId()',\r\n '[attr.hidden]': 'hidden()',\r\n },\r\n})\r\nexport class SkraTabPanel {\r\n /** Selection key — matched against the owning `button[skraTab]`'s `value`. */\r\n readonly value = input.required<string>();\r\n\r\n private readonly ctx = inject(SkraTabsContext, { optional: true });\r\n\r\n protected readonly panelId = computed(\r\n () => this.ctx?.panelId(this.value()) ?? null,\r\n );\r\n protected readonly tabId = computed(\r\n () => this.ctx?.tabId(this.value()) ?? null,\r\n );\r\n /** `''` (attribute present) when not selected → hidden; `null` (absent) when selected → shown. */\r\n protected readonly hidden = computed(() =>\r\n this.ctx?.isSelected(this.value()) ? null : '',\r\n );\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.ctx) {\r\n console.warn(\r\n '[skraTabPanel] has no [skraTabs] ancestor — it cannot be linked to a tab or shown/hidden. ' +\r\n 'Project it inside <element skraTabs>.',\r\n );\r\n }\r\n }\r\n }\r\n}\r\n","import { FocusKeyManager } from '@angular/cdk/a11y';\r\n\r\nimport type { SkraTabKeyItem } from './tabs-types';\r\n\r\n/**\r\n * SkraTabsKeyboard — the WAI-ARIA APG **Tabs** roving-tabindex keyboard model, confined to ONE file.\r\n *\r\n * This is the **only** module in `@skra/navigation` that imports `@angular/cdk` (ADR 0044 §7,\r\n * generalized library-wide 2026-06-19). It wraps CDK `FocusKeyManager` (roving REAL focus) so the\r\n * engine is swappable in one file — exactly as `SkraMenuKeyboard` does for the menu. Unlike the menu,\r\n * tabs use **horizontal** orientation (Left/Right) and **skip** disabled tabs.\r\n *\r\n * Owns: Left/Right roving (wrap), Home/End. Enter/Space (native button activation) and selection are\r\n * the coordinator's job — the controller only moves focus and reports the active tab's value.\r\n */\r\nexport class SkraTabsKeyboard {\r\n private manager?: FocusKeyManager<SkraTabKeyItem>;\r\n private items: SkraTabKeyItem[] = [];\r\n\r\n /**\r\n * (Re)build the manager from the current projected tab set. Called from an `effect` on the signal\r\n * `contentChildren` — a passed array is a static snapshot, so the manager is rebuilt whenever the\r\n * tab set changes (the documented signal↔CDK seam, mirroring `menu-keyboard.ts`).\r\n */\r\n setItems(items: readonly SkraTabKeyItem[]): void {\r\n this.items = [...items];\r\n this.manager?.destroy();\r\n this.manager = new FocusKeyManager<SkraTabKeyItem>(this.items)\r\n .withHorizontalOrientation('ltr') // Left/Right; RTL handled by the manager via the page dir\r\n .withWrap()\r\n .withHomeAndEnd()\r\n // Tabs SKIP disabled (APG): a disabled tab is not a roving stop. (Menu keeps them focusable.)\r\n .skipPredicate((tab) => tab.isDisabled());\r\n }\r\n\r\n /** Delegate Left/Right/Home/End. Enter/Space/Tab are intentionally left to the platform/coordinator. */\r\n onKeydown(event: KeyboardEvent): void {\r\n this.manager?.onKeydown(event);\r\n }\r\n\r\n /** The value of the tab the manager currently considers active (focused after `onKeydown`). */\r\n activeValue(): string | undefined {\r\n return this.manager?.activeItem?.getValue();\r\n }\r\n\r\n /** Sync the manager's active index to a value WITHOUT moving focus (after a click / on init). */\r\n setActive(value: string): void {\r\n const index = this.items.findIndex((tab) => tab.getValue() === value);\r\n if (index >= 0) this.manager?.updateActiveItem(index);\r\n }\r\n\r\n /** The first non-disabled tab's value (the roving stop when nothing is selected) — APG. */\r\n firstEnabledValue(): string | undefined {\r\n return this.items.find((tab) => !tab.isDisabled())?.getValue();\r\n }\r\n\r\n hasValue(value: string): boolean {\r\n return this.items.some((tab) => tab.getValue() === value);\r\n }\r\n\r\n destroy(): void {\r\n this.manager?.destroy();\r\n this.manager = undefined;\r\n }\r\n}\r\n","import {\r\n DestroyRef,\r\n Directive,\r\n contentChildren,\r\n effect,\r\n inject,\r\n input,\r\n output,\r\n} from '@angular/core';\r\n\r\nimport { SkraTab } from './tab';\r\nimport { SkraTabPanel } from './tab-panel';\r\nimport { SkraTabsContext } from './tabs-context';\r\nimport { SkraTabsKeyboard } from './tabs-keyboard';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTabs — the WAI-ARIA APG **Tabs** coordinator. A directive on a wrapping element that holds a\r\n * `[skraTablist]` (the `role=\"tablist\"` with its `button[skraTab]` children) and the\r\n * `[skraTabPanel]` panels as DI descendants. It provides `SkraTabsContext` (the ADR 013 §3.6 non-form\r\n * Contextual-ID-Sync bus), owns the consumer-facing `[selected]` / `(selectedChange)` (controlled,\r\n * ADR 037 — NO internal selection state) and `[activation]`, and drives the roving-tabindex keyboard\r\n * (`SkraTabsKeyboard` → CDK `FocusKeyManager`).\r\n *\r\n * <div skraTabs [selected]=\"tab()\" (selectedChange)=\"tab.set($event)\">\r\n * <div skraTablist aria-label=\"Account\">\r\n * <button skraTab value=\"profile\">Profile</button>\r\n * <button skraTab value=\"security\">Security</button>\r\n * </div>\r\n * <div skraTabPanel value=\"profile\">…</div>\r\n * <div skraTabPanel value=\"security\">…</div>\r\n * </div>\r\n *\r\n * Selection is consumer-owned: a click / Enter / Space / (automatic) arrow emits `(selectedChange)`;\r\n * the visible selection updates when the consumer round-trips `[selected]`. The roving focus position\r\n * (`tabindex=\"0\"`) is component-owned UI state — it moves immediately, independent of `[selected]`.\r\n *\r\n * Full contract: adr/specs/component-tabs-spec.md.\r\n */\r\n@Directive({\r\n selector: '[skraTabs]',\r\n standalone: true,\r\n exportAs: 'skraTabs',\r\n providers: [SkraTabsContext],\r\n})\r\nexport class SkraTabs {\r\n /** Consumer-owned selection key (matches a tab's `value`); '' / no-match → nothing selected (ADR 037). */\r\n readonly selected = input<string>('');\r\n /** Automatic (selection follows roving focus) | manual (Enter/Space selects). */\r\n readonly activation = input<'automatic' | 'manual'>('automatic');\r\n /** Fires ONLY on user activation — never on a programmatic `[selected]` change. */\r\n readonly selectedChange = output<string>();\r\n\r\n private readonly ctx = inject(SkraTabsContext);\r\n private readonly tabs = contentChildren(SkraTab, { descendants: true });\r\n private readonly panels = contentChildren(SkraTabPanel, {\r\n descendants: true,\r\n });\r\n private readonly keyboard = new SkraTabsKeyboard();\r\n\r\n constructor() {\r\n // Wire the context bus (a tab requests selection; the tablist forwards keydown).\r\n this.ctx.select = (value) => this.selectTab(value);\r\n this.ctx.handleKeydown = (event) => this.onTablistKeydown(event);\r\n\r\n // Mirror inputs → context (read-only to children).\r\n effect(() => this.ctx.selected.set(this.selected()));\r\n effect(() => this.ctx.activation.set(this.activation()));\r\n\r\n // (Re)build the keyboard from the projected tab set and (re)seat the roving stop whenever the tab\r\n // set or the selection changes. Rebuilding the manager for a handful of tabs is trivial.\r\n effect(() => {\r\n this.keyboard.setItems(this.tabs());\r\n this.reseat();\r\n });\r\n\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n effect(() => this.warnMismatches());\r\n }\r\n\r\n inject(DestroyRef).onDestroy(() => this.keyboard.destroy());\r\n }\r\n\r\n /** Seat the roving stop (`tabindex=\"0\"`) on a real, enabled tab: the selected one if valid, else the\r\n * first enabled tab (APG — the tablist must always have exactly one tab stop). */\r\n private reseat(): void {\r\n const sel = this.selected();\r\n const next = this.keyboard.hasValue(sel)\r\n ? sel\r\n : (this.keyboard.firstEnabledValue() ?? '');\r\n this.ctx.activeValue.set(next);\r\n if (next) this.keyboard.setActive(next);\r\n }\r\n\r\n /** A tab was activated (click / Enter / Space / automatic arrow). Move the roving stop immediately\r\n * (UI state), then REQUEST selection from the consumer — never mutate selection internally (ADR 037). */\r\n private selectTab(value: string): void {\r\n this.ctx.activeValue.set(value);\r\n this.keyboard.setActive(value);\r\n if (this.selected() === value) return; // idempotent — no redundant output\r\n this.selectedChange.emit(value);\r\n }\r\n\r\n private onTablistKeydown(event: KeyboardEvent): void {\r\n const before = this.keyboard.activeValue();\r\n this.keyboard.onKeydown(event);\r\n const after = this.keyboard.activeValue();\r\n if (after && after !== before) {\r\n this.ctx.activeValue.set(after); // roving moved (focus already on the new tab)\r\n if (this.ctx.activation() === 'automatic') this.selectTab(after);\r\n }\r\n }\r\n\r\n /** Dev-only nudge: every tab needs a panel of the same `value`, and vice-versa (aria-controls / -labelledby). */\r\n private warnMismatches(): void {\r\n const tabValues = new Set(this.tabs().map((t) => t.value()));\r\n const panelValues = new Set(this.panels().map((p) => p.value()));\r\n for (const v of tabValues) {\r\n if (!panelValues.has(v))\r\n console.warn(\r\n `[skraTabs] tab value=\"${v}\" has no matching [skraTabPanel] — its aria-controls points to a missing panel.`,\r\n );\r\n }\r\n for (const v of panelValues) {\r\n if (!tabValues.has(v))\r\n console.warn(\r\n `[skraTabs] panel value=\"${v}\" has no matching button[skraTab] — it will never be revealed.`,\r\n );\r\n }\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n inject,\r\n} from '@angular/core';\r\n\r\nimport { SkraTabsContext } from './tabs-context';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * SkraTablist — the `role=\"tablist\"` container, a Component on the consumer's `<div skraTablist>`\r\n * (ADR 040, `template: '<ng-content>'` so the projected `button[skraTab]` children render). It carries\r\n * the rail styling and forwards its `keydown` to the coordinator's roving keyboard (`SkraTabsKeyboard`)\r\n * via the `SkraTabsContext` bus. Name it for AT with consumer `aria-label`/`aria-labelledby` (ADR 033).\r\n */\r\n@Component({\r\n selector: '[skraTablist]',\r\n standalone: true,\r\n exportAs: 'skraTablist',\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './tablist.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'tablist',\r\n 'aria-orientation': 'horizontal',\r\n '(keydown)': 'onKeydown($event)',\r\n },\r\n})\r\nexport class SkraTablist {\r\n private readonly ctx = inject(SkraTabsContext, { optional: true });\r\n\r\n constructor() {\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n if (!this.ctx) {\r\n console.warn(\r\n '[skraTablist] has no [skraTabs] ancestor — its tabs cannot be keyboard-navigated. ' +\r\n 'Wrap the tablist + panels in <element skraTabs>.',\r\n );\r\n }\r\n }\r\n }\r\n\r\n protected onKeydown(event: KeyboardEvent): void {\r\n this.ctx?.handleKeydown(event);\r\n }\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ViewEncapsulation, ChangeDetectionStrategy, Component, Directive } from '@angular/core';
2
+ import { inject, ElementRef, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, Directive } from '@angular/core';
3
3
  import { SkraFieldContext } from '@skra/ui/field';
4
4
 
5
5
  /**
@@ -21,28 +21,54 @@ import { SkraFieldContext } from '@skra/ui/field';
21
21
  * <textarea skraTextarea skraAutoResize rows="3"></textarea>
22
22
  * </skra-field>
23
23
  *
24
+ * <!-- standalone: native implicit label (wrapping) — no id/for needed -->
25
+ * <label>Notes <textarea skraTextarea></textarea></label>
26
+ *
24
27
  * Native `rows` / `cols` remain the consumer-facing sizing primitives — Forge
25
28
  * does not duplicate them as Angular inputs (boundary #9 native-attr-first).
29
+ *
30
+ * `SkraFieldContext` is injected `{ optional: true }` (ADR 013 §3.7) — same
31
+ * posture as SkraInput / SkraCheckbox. Standalone, the atom renders the skin
32
+ * only and the consumer owns every attribute, including the accessible name.
26
33
  */
27
34
  class SkraTextarea {
28
- context = inject(SkraFieldContext);
29
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
30
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.7", type: SkraTextarea, isStandalone: true, selector: "textarea[skraTextarea]", host: { properties: { "id": "context.fieldId()", "attr.aria-describedby": "context.describedByIds()", "attr.aria-invalid": "context.hasError() ? \"true\" : null", "attr.aria-required": "context.isRequired() ? \"true\" : null", "attr.disabled": "context.isDisabled() ? \"\" : null", "attr.readonly": "context.isReadonly() ? \"\" : null" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
35
+ el = inject(ElementRef);
36
+ context = inject(SkraFieldContext, { optional: true });
37
+ constructor() {
38
+ const el = this.el.nativeElement;
39
+ // Field-cascaded native properties — only bind when context is present so
40
+ // standalone consumers retain full control of their static attributes.
41
+ // Mirrors SkraInput / SkraCheckbox.
42
+ if (this.context) {
43
+ const ctx = this.context;
44
+ effect(() => {
45
+ el.id = ctx.fieldId();
46
+ });
47
+ effect(() => {
48
+ el.disabled = ctx.isDisabled();
49
+ });
50
+ effect(() => {
51
+ el.readOnly = ctx.isReadonly();
52
+ });
53
+ }
54
+ }
55
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
56
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraTextarea, isStandalone: true, selector: "textarea[skraTextarea]", host: { properties: { "attr.aria-describedby": "context?.describedByIds() ?? null", "attr.aria-invalid": "context?.hasError() ? \"true\" : null", "attr.aria-required": "context?.isRequired() ? \"true\" : null" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
31
57
  }
32
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraTextarea, decorators: [{
58
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraTextarea, decorators: [{
33
59
  type: Component,
34
60
  args: [{ selector: 'textarea[skraTextarea]', standalone: true, template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
35
- '[id]': 'context.fieldId()',
36
- '[attr.aria-describedby]': 'context.describedByIds()',
37
- '[attr.aria-invalid]': 'context.hasError() ? "true" : null',
38
- '[attr.aria-required]': 'context.isRequired() ? "true" : null',
61
+ // ARIA relationships — Skra-owned, present only while a field cascades them.
62
+ '[attr.aria-describedby]': 'context?.describedByIds() ?? null',
63
+ '[attr.aria-invalid]': 'context?.hasError() ? "true" : null',
64
+ '[attr.aria-required]': 'context?.isRequired() ? "true" : null',
39
65
  // Availability — native attrs only (native-attr-first, boundary #9).
40
66
  // <textarea> supports native `readonly`/`disabled`; NO `aria-readonly`/
41
67
  // `aria-disabled` duplicate. Readonly styling keys off `:read-only`.
42
- '[attr.disabled]': 'context.isDisabled() ? "" : null',
43
- '[attr.readonly]': 'context.isReadonly() ? "" : null',
68
+ // Driven imperatively below, NOT as host bindings — see the constructor
69
+ // note on standalone attribute ownership.
44
70
  }, styles: [":host{background:var(--skra-comp-field-background);color:var(--skra-comp-field-foreground);border-color:var(--skra-comp-field-border-color);border-width:var(--skra-comp-field-border-width);border-style:var(--skra-comp-field-border-style);border-radius:var(--skra-comp-field-radius);padding-block:var(--skra-comp-field-padding-block);padding-inline:var(--skra-comp-field-padding-inline);box-shadow:var(--skra-comp-field-shadow);font:inherit;outline:none;transition:background-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),border-color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing),box-shadow var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host(:hover:not(:disabled):not([readonly])){background:var(--skra-comp-field-background-hover);border-color:var(--skra-comp-field-border-color-hover)}:host(:focus-visible){border-color:var(--skra-comp-field-focus-ring-color);box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-focus-ring-color)}:host(:disabled){cursor:not-allowed;opacity:var(--skra-sys-opacity-disabled)}:host([readonly]){cursor:default}:host([aria-invalid=true]){border-color:var(--skra-comp-field-error-color)}:host([aria-invalid=true]:focus-visible){box-shadow:0 0 0 var(--skra-comp-field-focus-ring-width) var(--skra-comp-field-error-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
45
- }] });
71
+ }], ctorParameters: () => [] });
46
72
 
47
73
  /**
48
74
  * Marker directive enabling content-driven sizing on a native form control via
@@ -62,10 +88,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
62
88
  * input grows in inline-size with content width.
63
89
  */
64
90
  class SkraAutoResizeDirective {
65
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraAutoResizeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
66
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.7", type: SkraAutoResizeDirective, isStandalone: true, selector: "textarea[skraAutoResize], input[skraAutoResize]", ngImport: i0 });
91
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraAutoResizeDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
92
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "22.1.1", type: SkraAutoResizeDirective, isStandalone: true, selector: "textarea[skraAutoResize], input[skraAutoResize]", ngImport: i0 });
67
93
  }
68
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SkraAutoResizeDirective, decorators: [{
94
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraAutoResizeDirective, decorators: [{
69
95
  type: Directive,
70
96
  args: [{
71
97
  selector: 'textarea[skraAutoResize], input[skraAutoResize]',
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-textarea.mjs","sources":["../../../../libs/ui/textarea/src/lib/textarea/textarea.ts","../../../../libs/ui/textarea/src/lib/auto-resize/auto-resize.directive.ts","../../../../libs/ui/textarea/src/skra-ui-textarea.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * `textarea[skraTextarea]` — multiline text atom. Per ADR 040 this is a\n * Component-on-a-native-host carrying its own host-scoped CSS (`textarea.scss`)\n * via Emulated encapsulation, replacing the ADR 038 slice branch.\n *\n * `<textarea>` is a content-bearing host (its value is its text content), so the\n * template MUST be `<ng-content>` — `template: ''` would discard the consumer's\n * initial text. See ADR 040 §2.\n *\n * Sibling atom to SkraInput — split per atom-granularity rule (memory\n * `feedback_atom_granularity.md`): textarea has capabilities `<input>` does not\n * (multi-line content, native `rows` / `cols`, autosize composition via the\n * sibling `[skraAutoResize]` directive).\n *\n * <skra-field>\n * <label skraLabelFor>Bio</label>\n * <textarea skraTextarea skraAutoResize rows=\"3\"></textarea>\n * </skra-field>\n *\n * Native `rows` / `cols` remain the consumer-facing sizing primitives — Forge\n * does not duplicate them as Angular inputs (boundary #9 native-attr-first).\n */\n@Component({\n selector: 'textarea[skraTextarea]',\n standalone: true,\n // Content-bearing host — see ADR 040 §2.\n template: '<ng-content></ng-content>',\n styleUrl: './textarea.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n '[id]': 'context.fieldId()',\n '[attr.aria-describedby]': 'context.describedByIds()',\n '[attr.aria-invalid]': 'context.hasError() ? \"true\" : null',\n '[attr.aria-required]': 'context.isRequired() ? \"true\" : null',\n // Availability — native attrs only (native-attr-first, boundary #9).\n // <textarea> supports native `readonly`/`disabled`; NO `aria-readonly`/\n // `aria-disabled` duplicate. Readonly styling keys off `:read-only`.\n '[attr.disabled]': 'context.isDisabled() ? \"\" : null',\n '[attr.readonly]': 'context.isReadonly() ? \"\" : null',\n },\n})\nexport class SkraTextarea {\n readonly context = inject(SkraFieldContext);\n}\n","import { Directive } from '@angular/core';\n\n/**\n * Marker directive enabling content-driven sizing on a native form control via\n * the modern CSS `field-sizing: content` declaration shipped from the skin's\n * global utilities layer (`tokens/skins/skra/utilities.scss`).\n *\n * <textarea skraTextarea skraAutoResize rows=\"2\"></textarea>\n * <input skraInput skraAutoResize type=\"text\" />\n *\n * Composition-over-configuration: the host opts in by adding the attribute,\n * not by toggling a boolean Angular input. The directive has no host bindings,\n * no DI, and no template — its sole job is to make the selector available at\n * Angular's compilation stage; CSS does the rest.\n *\n * Wide selector (textarea + input) reflects that `field-sizing: content` is a\n * native CSS capability for both: textarea grows in block-size with rows,\n * input grows in inline-size with content width.\n */\n@Directive({\n selector: 'textarea[skraAutoResize], input[skraAutoResize]',\n standalone: true,\n})\nexport class SkraAutoResizeDirective {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAQA;;;;;;;;;;;;;;;;;;;;;AAqBG;MAqBU,YAAY,CAAA;AACd,IAAA,OAAO,GAAG,MAAM,CAAC,gBAAgB,CAAC;uGADhC,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAY,uaAhBb,2BAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,i/CAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAgB1B,YAAY,EAAA,UAAA,EAAA,CAAA;kBApBxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,UAAA,EACtB,IAAI,EAAA,QAAA,EAEN,2BAA2B,EAAA,eAAA,EAEpB,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;AACJ,wBAAA,MAAM,EAAE,mBAAmB;AAC3B,wBAAA,yBAAyB,EAAE,0BAA0B;AACrD,wBAAA,qBAAqB,EAAE,oCAAoC;AAC3D,wBAAA,sBAAsB,EAAE,sCAAsC;;;;AAI9D,wBAAA,iBAAiB,EAAE,kCAAkC;AACrD,wBAAA,iBAAiB,EAAE,kCAAkC;AACtD,qBAAA,EAAA,MAAA,EAAA,CAAA,i/CAAA,CAAA,EAAA;;;AC9CH;;;;;;;;;;;;;;;;AAgBG;MAKU,uBAAuB,CAAA;uGAAvB,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAvB,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iDAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAvB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAJnC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,iDAAiD;AAC3D,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;ACtBD;;AAEG;;;;"}
1
+ {"version":3,"file":"skra-ui-textarea.mjs","sources":["../../../../libs/ui/textarea/src/lib/textarea/textarea.ts","../../../../libs/ui/textarea/src/lib/auto-resize/auto-resize.directive.ts","../../../../libs/ui/textarea/src/skra-ui-textarea.ts"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n effect,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '@skra/ui/field';\n\n/**\n * `textarea[skraTextarea]` — multiline text atom. Per ADR 040 this is a\n * Component-on-a-native-host carrying its own host-scoped CSS (`textarea.scss`)\n * via Emulated encapsulation, replacing the ADR 038 slice branch.\n *\n * `<textarea>` is a content-bearing host (its value is its text content), so the\n * template MUST be `<ng-content>` — `template: ''` would discard the consumer's\n * initial text. See ADR 040 §2.\n *\n * Sibling atom to SkraInput — split per atom-granularity rule (memory\n * `feedback_atom_granularity.md`): textarea has capabilities `<input>` does not\n * (multi-line content, native `rows` / `cols`, autosize composition via the\n * sibling `[skraAutoResize]` directive).\n *\n * <skra-field>\n * <label skraLabelFor>Bio</label>\n * <textarea skraTextarea skraAutoResize rows=\"3\"></textarea>\n * </skra-field>\n *\n * <!-- standalone: native implicit label (wrapping) — no id/for needed -->\n * <label>Notes <textarea skraTextarea></textarea></label>\n *\n * Native `rows` / `cols` remain the consumer-facing sizing primitives — Forge\n * does not duplicate them as Angular inputs (boundary #9 native-attr-first).\n *\n * `SkraFieldContext` is injected `{ optional: true }` (ADR 013 §3.7) — same\n * posture as SkraInput / SkraCheckbox. Standalone, the atom renders the skin\n * only and the consumer owns every attribute, including the accessible name.\n */\n@Component({\n selector: 'textarea[skraTextarea]',\n standalone: true,\n // Content-bearing host — see ADR 040 §2.\n template: '<ng-content></ng-content>',\n styleUrl: './textarea.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // ARIA relationships — Skra-owned, present only while a field cascades them.\n '[attr.aria-describedby]': 'context?.describedByIds() ?? null',\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\n '[attr.aria-required]': 'context?.isRequired() ? \"true\" : null',\n // Availability — native attrs only (native-attr-first, boundary #9).\n // <textarea> supports native `readonly`/`disabled`; NO `aria-readonly`/\n // `aria-disabled` duplicate. Readonly styling keys off `:read-only`.\n // Driven imperatively below, NOT as host bindings — see the constructor\n // note on standalone attribute ownership.\n },\n})\nexport class SkraTextarea {\n private readonly el = inject<ElementRef<HTMLTextAreaElement>>(ElementRef);\n readonly context = inject(SkraFieldContext, { optional: true });\n\n constructor() {\n const el = this.el.nativeElement;\n\n // Field-cascaded native properties — only bind when context is present so\n // standalone consumers retain full control of their static attributes.\n // Mirrors SkraInput / SkraCheckbox.\n if (this.context) {\n const ctx = this.context;\n effect(() => {\n el.id = ctx.fieldId();\n });\n effect(() => {\n el.disabled = ctx.isDisabled();\n });\n effect(() => {\n el.readOnly = ctx.isReadonly();\n });\n }\n }\n}\n","import { Directive } from '@angular/core';\r\n\r\n/**\r\n * Marker directive enabling content-driven sizing on a native form control via\r\n * the modern CSS `field-sizing: content` declaration shipped from the skin's\r\n * global utilities layer (`tokens/skins/skra/utilities.scss`).\r\n *\r\n * <textarea skraTextarea skraAutoResize rows=\"2\"></textarea>\r\n * <input skraInput skraAutoResize type=\"text\" />\r\n *\r\n * Composition-over-configuration: the host opts in by adding the attribute,\r\n * not by toggling a boolean Angular input. The directive has no host bindings,\r\n * no DI, and no template — its sole job is to make the selector available at\r\n * Angular's compilation stage; CSS does the rest.\r\n *\r\n * Wide selector (textarea + input) reflects that `field-sizing: content` is a\r\n * native CSS capability for both: textarea grows in block-size with rows,\r\n * input grows in inline-size with content width.\r\n */\r\n@Directive({\r\n selector: 'textarea[skraAutoResize], input[skraAutoResize]',\r\n standalone: true,\r\n})\r\nexport class SkraAutoResizeDirective {}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;;AAUA;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BG;MAqBU,YAAY,CAAA;AACN,IAAA,EAAE,GAAG,MAAM,CAAkC,UAAU,CAAC;IAChE,OAAO,GAAG,MAAM,CAAC,gBAAgB,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAE/D,IAAA,WAAA,GAAA;AACE,QAAA,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC,aAAa;;;;AAKhC,QAAA,IAAI,IAAI,CAAC,OAAO,EAAE;AAChB,YAAA,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO;YACxB,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE;AACvB,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;YACF,MAAM,CAAC,MAAK;AACV,gBAAA,EAAE,CAAC,QAAQ,GAAG,GAAG,CAAC,UAAU,EAAE;AAChC,YAAA,CAAC,CAAC;QACJ;IACF;uGAtBW,YAAY,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAZ,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,YAAY,ySAhBb,2BAA2B,EAAA,QAAA,EAAA,IAAA,EAAA,MAAA,EAAA,CAAA,i/CAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FAgB1B,YAAY,EAAA,UAAA,EAAA,CAAA;kBApBxB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,wBAAwB,EAAA,UAAA,EACtB,IAAI,EAAA,QAAA,EAEN,2BAA2B,EAAA,eAAA,EAEpB,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,yBAAyB,EAAE,mCAAmC;AAC9D,wBAAA,qBAAqB,EAAE,qCAAqC;AAC5D,wBAAA,sBAAsB,EAAE,uCAAuC;;;;;;AAMhE,qBAAA,EAAA,MAAA,EAAA,CAAA,i/CAAA,CAAA,EAAA;;;ACvDH;;;;;;;;;;;;;;;;AAgBG;MAKU,uBAAuB,CAAA;uGAAvB,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAvB,uBAAuB,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,iDAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAvB,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAJnC,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,iDAAiD;AAC3D,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;ACtBD;;AAEG;;;;"}