@skra/ui 0.3.0 → 0.4.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.
@@ -58,7 +58,7 @@ Violating these is a review blocker in a consumer repo just as inside Skra.
58
58
  | **Accessible names** | `accessible-names.md` | Naming buttons, icon-only controls, overlays; using `skra-sr-only` | ✅ draft |
59
59
  | **Theming & encapsulation** | `theming-and-encapsulation.md` | Skins, dark mode, density; mounting under Shadow DOM / a microfrontend / an iframe | ✅ draft |
60
60
  | **Overlays** | `overlays.md` | Dialog / tooltip / popover / menu / select in the top layer; shadow & iframe limits | ✅ draft |
61
- | **Layout** | `layout.md` | Spacing & composition with Stack / Box / Grid; the gap scale | ✅ draft |
61
+ | **Layout** | `layout.md` | Spacing & composition with Stack / Box / Surface / Grid; building a card; the gap scale | ✅ draft |
62
62
  | **Wrapping Skra** | `wrapping-patterns.md` | Building your own higher-level components over Skra atoms (simplified API) | ✅ draft |
63
63
 
64
64
  ---
@@ -75,6 +75,7 @@ Violating these is a review blocker in a consumer repo just as inside Skra.
75
75
  | Mount Skra inside a Web Component / microfrontend | `theming-and-encapsulation.md` |
76
76
  | Open a dialog or tooltip | `overlays.md` |
77
77
  | Space components apart | `layout.md` |
78
+ | Build a card / panel / tile (there is no `skra-card`) | `layout.md` (Surface) |
78
79
  | Wrap a Skra atom in a project-specific component | `wrapping-patterns.md` |
79
80
 
80
81
  ---
@@ -69,6 +69,85 @@ A semantically-neutral padding primitive. Does **not** arrange children (no list
69
69
  <section skraBox padding="lg">…</section>
70
70
  ```
71
71
 
72
+ ## Surface — the painted container (`[skraSurface]`)
73
+
74
+ Box's **painting** sibling: background, border, radius, shadow — plus its own padding. Same
75
+ host allowlist as Box (`div`/`section`/`article`/`main`/`nav`/`aside`/`header`/`footer`/`figure`).
76
+
77
+ | Input | Values | Default |
78
+ | --- | --- | --- |
79
+ | `padding` | `none` \| `sm` \| `md` \| `lg` | **`md`** |
80
+
81
+ That is the whole API. Note the default differs from Box's `none` — Box is spacing-neutral by
82
+ construction, a painted container is not.
83
+
84
+ **Pick Box _or_ Surface per host, never both.** Box = spacing only; Surface = spacing + paint.
85
+
86
+ ### There is no `<skra-card>`, and you do not need one
87
+
88
+ "Card", "panel", "tile", "row" and "list item" are **compositions you write**, not Skra
89
+ components (ADR 0053). Strip padding, inner arrangement and sectioning semantics from a card
90
+ and what is left is a painted container — that is Surface, and that is all Skra ships:
91
+
92
+ ```html
93
+ <article skraSurface padding="lg" aria-labelledby="run-title">
94
+ <div skraStack direction="column" gap="md">
95
+ <h3 id="run-title" skraTypography="title-small">Morning run</h3>
96
+ <p skraTypography="body-medium">5.2 km · 24:31</p>
97
+ </div>
98
+ </article>
99
+ ```
100
+
101
+ You own the sectioning element and the accessible name — Surface sets **no** `role`, no
102
+ `tabindex` and no `aria-*`. Pair it with `[skraGrid]` above for a responsive card grid with no
103
+ breakpoints.
104
+
105
+ ### Selection: Surface READS your markup, it never owns state
106
+
107
+ There is no `selected` input, and there never will be one — `aria-selected` is only valid on
108
+ `option`/`row`/`gridcell`/`tab` roles, so a component that bakes no role cannot emit it without
109
+ producing invalid ARIA. Instead, Surface paints a selected state when **your own markup** says
110
+ so, from exactly two signals:
111
+
112
+ | Your markup | When it is the right one |
113
+ | --- | --- |
114
+ | `aria-current="true"` (or `page` / `step` / `date`) on the Surface host | the current item of a set — a global ARIA state, so it is valid on a role-less `<article>` |
115
+ | `aria-selected="true"` on a host that **already** carries `option`/`row`/`gridcell`/`tab` | only inside a listbox / grid / tablist you actually built |
116
+
117
+ ```html
118
+ <article skraSurface padding="md" aria-current="true" aria-labelledby="t">…</article>
119
+ ```
120
+
121
+ `aria-current="false"` and `aria-selected="false"` are explicit *not*-current and paint as
122
+ resting.
123
+
124
+ **Gotcha — a checked control inside the card is NOT a signal.** A card wrapping a checked
125
+ `<input type="checkbox">`/`radio` does **not** light up, deliberately: `[skraSwitch]` and
126
+ `<skra-star-rating>` are themselves native checkbox/radio hosts, so inferring selection from a
127
+ descendant would paint every settings card and every rating card as "selected" while nothing in
128
+ the accessibility tree said so.
129
+
130
+ So for a **radio-group card picker** today, the selected state is carried by the radio's own
131
+ indicator and the card stays neutral. Do **not** reach for `aria-current` to force the paint
132
+ there: the radio already announces "selected", and adding `aria-current` makes assistive
133
+ technology announce one fact twice under two names. A dedicated marker for that shape is a known
134
+ gap (Skra-side `[skraSurfaceSelect]`), not something to emulate with a class.
135
+
136
+ ### Interactive (clickable) cards are not shipped yet
137
+
138
+ Surface is a container, not a widget, and the host allowlist deliberately excludes `a` and
139
+ `button`: `<button>` cannot legally contain flow content (its content model is phrasing content
140
+ with no interactive descendant), and an `<a>` wrapping the whole card takes the card's **entire**
141
+ text as its accessible name — which `aria-label` may not fix (Iron Rule 3).
142
+
143
+ Until the stretched-link marker ships, put a normal `a[skraLink]`/`button[skraButton]` **inside**
144
+ the card and let it be the target. Do not make the card itself clickable with a `(click)` on a
145
+ `<div>` — that fails keyboard access (WCAG 2.1.1) and has no role.
146
+
147
+ **Hover:** Surface has no hover state in v1, and there is no `hoverable` input — an
148
+ informational card correctly stays inert. If you add your own hover paint in app CSS, gate it
149
+ behind `@media (hover: hover) and (pointer: fine)`, or it will latch after every tap on touch.
150
+
72
151
  ## Grid — 2D (`[skraGrid]`)
73
152
 
74
153
  Bucket-only CSS Grid. The default `columns="auto-fit"` + `min` gives an intrinsically
@@ -16,7 +16,7 @@ entry exports nothing — always import from a `@skra/ui/<entry>` subpath.
16
16
  | `@skra/ui/link` | `a[skraLink]` |
17
17
  | `@skra/ui/icon` | icon container atom |
18
18
  | `@skra/ui/typography` | `[skraTypography]` |
19
- | `@skra/ui/layout` | `[skraStack]`, `[skraBox]`, `[skraGrid]` |
19
+ | `@skra/ui/layout` | `[skraStack]`, `[skraBox]`, `[skraGrid]`, `[skraSurface]` |
20
20
  | `@skra/ui/kbd` | `kbd[skraKbd]` |
21
21
  | `@skra/ui/field` | `<skra-field>`, `[skraLabel]`, `[skraHint]`, `[skraError]`, `fieldset[skraFieldset]`, `legend[skraLegend]`, `SkraFieldContext` |
22
22
  | `@skra/ui/input` | `input[skraInput]` |
@@ -95,7 +95,7 @@ on an ancestor**, never inline:
95
95
  ## Gotcha 3 — components carry `margin: 0` (ADR 022)
96
96
 
97
97
  Spacing between components is **never** a margin on the component. Use a layout atom
98
- (`[skraStack]`/`[skraBox]`/`[skraGrid]`) — see `layout.md`.
98
+ (`[skraStack]`/`[skraBox]`/`[skraGrid]`) — see `layout.md`. A painted container (card / panel) is `[skraSurface]`, which owns its own padding.
99
99
 
100
100
  ## Gotcha 4 — `skraTypography` takes its role **on the selector**, not a `role` input
101
101
 
@@ -126,24 +126,29 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
126
126
  * moved here from the slice).
127
127
  */
128
128
  class SkraLabel {
129
- context = inject(SkraFieldContext);
129
+ // Optional per ADR 013 §3.7 — outside `<skra-field>` the label still carries the
130
+ // skin and the consumer owns association (a wrapping `<label>`, or a hand-written
131
+ // `for`). Mandatory injection would crash the app for a styling-only use.
132
+ context = inject(SkraFieldContext, { optional: true });
130
133
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraLabel, deps: [], target: i0.ɵɵFactoryTarget.Component });
131
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraLabel, isStandalone: true, selector: "label[skraLabelFor]", host: { properties: { "htmlFor": "context.fieldId()", "id": "context.labelId()", "attr.data-skra-required": "context.isRequired() ? \"\" : null" }, classAttribute: "skra-label" }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{color:var(--skra-comp-field-label-color);font-family:var(--skra-sys-typography-role-label-medium-font-family);font-size:var(--skra-sys-typography-role-label-medium-font-size);font-weight:var(--skra-sys-typography-role-label-medium-font-weight);line-height:var(--skra-sys-typography-role-label-medium-line-height);letter-spacing:var(--skra-sys-typography-role-label-medium-letter-spacing);cursor:var(--skra-comp-field-label-cursor, pointer);transition:color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host([data-skra-required]):after{content:\"*\"/\"\";margin-inline-start:var(--skra-sys-spacing-1);color:var(--skra-comp-field-required-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
134
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraLabel, isStandalone: true, selector: "label[skraLabelFor]", host: { properties: { "attr.for": "context?.fieldId() ?? null", "attr.id": "context?.labelId() ?? null", "attr.data-skra-required": "context?.isRequired() ? \"\" : null" }, classAttribute: "skra-label" }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{color:var(--skra-comp-field-label-color);font-family:var(--skra-sys-typography-role-label-medium-font-family);font-size:var(--skra-sys-typography-role-label-medium-font-size);font-weight:var(--skra-sys-typography-role-label-medium-font-weight);line-height:var(--skra-sys-typography-role-label-medium-line-height);letter-spacing:var(--skra-sys-typography-role-label-medium-letter-spacing);cursor:var(--skra-comp-field-label-cursor, pointer);transition:color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host([data-skra-required]):after{content:\"*\"/\"\";margin-inline-start:var(--skra-sys-spacing-1);color:var(--skra-comp-field-required-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
132
135
  }
133
136
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraLabel, decorators: [{
134
137
  type: Component,
135
138
  args: [{ selector: 'label[skraLabelFor]', standalone: true, template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
136
- // The magic: auto-linking label to input via shared Context ID
137
- '[htmlFor]': 'context.fieldId()',
139
+ // The magic: auto-linking label to input via shared Context ID. Bound as an
140
+ // ATTRIBUTE, not the `htmlFor` property — with no field context the property
141
+ // form would stringify `undefined` into `for="undefined"`.
142
+ '[attr.for]': 'context?.fieldId() ?? null',
138
143
  // Referenceable id so a non-labelable control (a `role="radiogroup"` host like
139
144
  // <skra-star-rating>, which `for`/`id` can't target) can name itself via
140
145
  // `aria-labelledby`. Harmless for labelable controls (they use `for`). ADR 013.
141
- '[id]': 'context.labelId()',
146
+ '[attr.id]': 'context?.labelId() ?? null',
142
147
  // Required marker — reflect the field's required state so the SCSS can paint a
143
148
  // decorative asterisk (::after). The control already carries `aria-required`,
144
149
  // so the marker is purely visual (ADR 021 data-attr reflection; ADR 033 keeps
145
150
  // it out of the accessible name via the empty alt-text in `content`).
146
- '[attr.data-skra-required]': 'context.isRequired() ? "" : null',
151
+ '[attr.data-skra-required]': 'context?.isRequired() ? "" : null',
147
152
  // Class hook retained for any consumer-side targeting (ADR 024 pattern).
148
153
  class: 'skra-label',
149
154
  }, styles: [":host{color:var(--skra-comp-field-label-color);font-family:var(--skra-sys-typography-role-label-medium-font-family);font-size:var(--skra-sys-typography-role-label-medium-font-size);font-weight:var(--skra-sys-typography-role-label-medium-font-weight);line-height:var(--skra-sys-typography-role-label-medium-line-height);letter-spacing:var(--skra-sys-typography-role-label-medium-letter-spacing);cursor:var(--skra-comp-field-label-cursor, pointer);transition:color var(--skra-comp-field-motion-duration) var(--skra-comp-field-motion-easing)}:host([data-skra-required]):after{content:\"*\"/\"\";margin-inline-start:var(--skra-sys-spacing-1);color:var(--skra-comp-field-required-color)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
@@ -154,16 +159,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
154
159
  * Auto-receives ID from SkraFieldContext so aria-describedby on input works automatically.
155
160
  */
156
161
  class SkraHint {
157
- context = inject(SkraFieldContext);
162
+ // Optional per ADR 013 §3.7 — mirrors SkraError. Outside `<skra-field>` it
163
+ // publishes no id and is plain styled helper text the consumer associates itself.
164
+ context = inject(SkraFieldContext, { optional: true });
158
165
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraHint, deps: [], target: i0.ɵɵFactoryTarget.Component });
159
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraHint, isStandalone: true, selector: "skra-hint", host: { attributes: { "role": "note" }, properties: { "id": "context.hintId()" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{margin:0;display:block;font-family:var(--skra-sys-typography-role-body-small-font-family);font-size:var(--skra-sys-typography-role-body-small-font-size);font-weight:var(--skra-sys-typography-role-body-small-font-weight);line-height:var(--skra-sys-typography-role-body-small-line-height);letter-spacing:var(--skra-sys-typography-role-body-small-letter-spacing);color:var(--skra-comp-field-hint-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
166
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraHint, isStandalone: true, selector: "skra-hint", host: { attributes: { "role": "note" }, properties: { "attr.id": "context?.hintId() ?? null" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{margin:0;display:block;font-family:var(--skra-sys-typography-role-body-small-font-family);font-size:var(--skra-sys-typography-role-body-small-font-size);font-weight:var(--skra-sys-typography-role-body-small-font-weight);line-height:var(--skra-sys-typography-role-body-small-line-height);letter-spacing:var(--skra-sys-typography-role-body-small-letter-spacing);color:var(--skra-comp-field-hint-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
160
167
  }
161
168
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraHint, decorators: [{
162
169
  type: Component,
163
170
  args: [{ selector: 'skra-hint', standalone: true, template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
164
171
  // Zero-margin reset (ADR 022) lives in hint.component.scss `:host`.
165
172
  // ID linked from context — input's aria-describedby points here automatically
166
- '[id]': 'context.hintId()',
173
+ '[attr.id]': 'context?.hintId() ?? null',
167
174
  role: 'note',
168
175
  }, styles: [":host{margin:0;display:block;font-family:var(--skra-sys-typography-role-body-small-font-family);font-size:var(--skra-sys-typography-role-body-small-font-size);font-weight:var(--skra-sys-typography-role-body-small-font-weight);line-height:var(--skra-sys-typography-role-body-small-line-height);letter-spacing:var(--skra-sys-typography-role-body-small-letter-spacing);color:var(--skra-comp-field-hint-color)}\n"] }]
169
176
  }] });
@@ -200,16 +207,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
200
207
  * loaded two responsibilities into a single primitive.
201
208
  */
202
209
  class SkraError {
203
- context = inject(SkraFieldContext);
210
+ // Optional per ADR 013 §3.7. A GROUP-level error is a first-class pattern:
211
+ // `<skra-error>` sits as a direct child of `<fieldset skraFieldset>`, outside any
212
+ // `<skra-field>`, to carry one message for a radio/checkbox group (see the
213
+ // Fieldset `WithGroupError` story). It then publishes no id — nothing points at
214
+ // it via `aria-describedby`, and `role="alert"` announces it on its own.
215
+ context = inject(SkraFieldContext, { optional: true });
204
216
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraError, deps: [], target: i0.ɵɵFactoryTarget.Component });
205
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraError, isStandalone: true, selector: "skra-error", host: { attributes: { "role": "alert" }, properties: { "id": "context.errorId()" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{margin:0;display:block;font-family:var(--skra-sys-typography-role-body-small-font-family);font-size:var(--skra-sys-typography-role-body-small-font-size);font-weight:var(--skra-sys-typography-role-body-small-font-weight);line-height:var(--skra-sys-typography-role-body-small-line-height);letter-spacing:var(--skra-sys-typography-role-body-small-letter-spacing);color:var(--skra-comp-field-error-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
217
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.1", type: SkraError, isStandalone: true, selector: "skra-error", host: { attributes: { "role": "alert" }, properties: { "attr.id": "context?.errorId() ?? null" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{margin:0;display:block;font-family:var(--skra-sys-typography-role-body-small-font-family);font-size:var(--skra-sys-typography-role-body-small-font-size);font-weight:var(--skra-sys-typography-role-body-small-font-weight);line-height:var(--skra-sys-typography-role-body-small-line-height);letter-spacing:var(--skra-sys-typography-role-body-small-letter-spacing);color:var(--skra-comp-field-error-color)}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
206
218
  }
207
219
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraError, decorators: [{
208
220
  type: Component,
209
221
  args: [{ selector: 'skra-error', standalone: true, template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
210
222
  // Zero-margin reset (ADR 022) lives in error.component.scss `:host`.
211
223
  // ID linked from context — input's aria-describedby points here automatically
212
- '[id]': 'context.errorId()',
224
+ '[attr.id]': 'context?.errorId() ?? null',
213
225
  // role="alert" implies aria-live="assertive" + aria-atomic="true" — do NOT
214
226
  // add an explicit aria-live (contradicts the implicit assertive). Errors are
215
227
  // announced promptly per WAI-ARIA APG.
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-field.mjs","sources":["../../../../libs/ui/field/src/lib/id-generator/id-generator.service.ts","../../../../libs/ui/field/src/lib/field-context/field-context.ts","../../../../libs/ui/field/src/lib/field/field.component.ts","../../../../libs/ui/field/src/lib/label/label.ts","../../../../libs/ui/field/src/lib/hint/hint.component.ts","../../../../libs/ui/field/src/lib/error/error.component.ts","../../../../libs/ui/field/src/lib/fieldset/fieldset.ts","../../../../libs/ui/field/src/lib/fieldset/legend.ts","../../../../libs/ui/field/src/index.ts","../../../../libs/ui/field/src/skra-ui-field.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\n\r\n/**\r\n * Root-level service generating unique, short IDs for form elements.\r\n * Implements ADR 013 — deterministic IDs without bloaty UUID libraries.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class IdGeneratorService {\r\n private counter = 0;\r\n\r\n nextId(prefix = 'fg'): string {\r\n return `${prefix}-${++this.counter}`;\r\n }\r\n}\r\n","import { Injectable, signal, computed } from '@angular/core';\r\n\r\n/**\r\n * DI Context service provided per SkraField instance.\r\n * Acts as the synchronization bus between Field, Input, Label, Hint, and Error.\r\n * Implements ADR 013: Signal-based Contextual Interaction.\r\n */\r\n@Injectable()\r\nexport class SkraFieldContext {\r\n readonly fieldId = signal<string>('');\r\n readonly hasError = signal<boolean>(false);\r\n readonly isDisabled = signal<boolean>(false);\r\n readonly isRequired = signal<boolean>(false);\r\n readonly isReadonly = signal<boolean>(false);\r\n\r\n // Derived IDs for aria-describedby linkage\r\n readonly hintId = computed(() => `${this.fieldId()}-hint`);\r\n readonly errorId = computed(() => `${this.fieldId()}-error`);\r\n\r\n // Derived label ID. Labelable controls (input/checkbox/radio) associate via the\r\n // native `for`/`id` pair, so they never needed a referenceable label id. A\r\n // `role=\"radiogroup\"` host (<skra-star-rating>) is NOT labelable by `for`, so it\r\n // must name itself via `aria-labelledby` → the label needs an id. This is the third\r\n // derived id alongside hintId/errorId — an id, never a value (ADR 013 §3.6; the\r\n // context carries id + derived state only). Set on `label[skraLabelFor]`.\r\n readonly labelId = computed(() => `${this.fieldId()}-label`);\r\n\r\n // Combined aria-describedby tokens for the input/textarea host.\r\n // Both ids are always emitted — when <skra-hint> or <skra-error> is not\r\n // rendered, the matching DOM node is absent and browsers / screen readers\r\n // gracefully ignore the dangling reference. Simpler than tracking presence\r\n // via contentChild queries from the directive (which has no template).\r\n readonly describedByIds = computed(\r\n () => `${this.hintId()} ${this.errorId()}`,\r\n );\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n OnInit,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '../field-context/field-context';\r\nimport { IdGeneratorService } from '../id-generator/id-generator.service';\r\n\r\n@Component({\r\n selector: 'skra-field',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './field.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n // KEY: provides a new SkraFieldContext instance per field — isolation guaranteed\r\n providers: [SkraFieldContext],\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021). The layout reset (margin) +\r\n // display:flex live in field.component.scss `:host` (ADR 022) — host-metadata\r\n // bare keys (margin, display) render as junk attributes with no styling effect.\r\n // Validation state (ADR 027) — canonical `data-skra-validation=\"invalid\"`,\r\n // NOT the forbidden `data-skra-has-error` (migrated 2026-05-31 per ADR 027\r\n // §3.6 / state-surface-catalog). The control's `aria-invalid` lives on the\r\n // inner <input skraInput> (ADR 013), not on this group host.\r\n '[attr.data-skra-validation]': 'context.hasError() ? \"invalid\" : null',\r\n '[attr.data-skra-disabled]': 'context.isDisabled() ? \"\" : null',\r\n '[attr.data-skra-required]': 'context.isRequired() ? \"\" : null',\r\n '[attr.data-skra-readonly]': 'context.isReadonly() ? \"\" : null',\r\n\r\n // A11y: role=\"group\" groups label+input+hint semantically for screen readers\r\n role: 'group',\r\n },\r\n})\r\nexport class SkraField implements OnInit {\r\n private readonly idGen = inject(IdGeneratorService);\r\n readonly context = inject(SkraFieldContext);\r\n\r\n readonly fieldId = input<string | null>(null);\r\n readonly readonly = input(false, { transform: booleanAttribute });\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n readonly required = input(false, { transform: booleanAttribute });\r\n readonly hasError = input(false, { transform: booleanAttribute });\r\n\r\n constructor() {\r\n // Reactive sync — state inputs propagate to SkraFieldContext on every\r\n // change (not just on init). Replaces the previous ngOnInit-only pattern\r\n // which caused late input changes to silently desync from the context\r\n // (and from sibling atoms reading the context). Matches Checkbox's\r\n // effect() pattern for indeterminate property sync.\r\n effect(() => {\r\n this.context.isReadonly.set(this.readonly());\r\n this.context.isDisabled.set(this.disabled());\r\n this.context.isRequired.set(this.required());\r\n this.context.hasError.set(this.hasError());\r\n });\r\n }\r\n\r\n // fieldId is one-shot — assigned once on init, never changes thereafter\r\n // (a field's identity attribute should be stable for the field's lifetime).\r\n ngOnInit(): void {\r\n this.context.fieldId.set(this.fieldId() ?? this.idGen.nextId('fg'));\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\nimport { SkraFieldContext } from '../field-context/field-context';\r\n\r\n/**\r\n * `label[skraLabelFor]` — form-control label atom. Per ADR 040 this is a\r\n * Component-on-the-native-host carrying its own `label.scss` (typography + colour\r\n * + cursor) via Emulated encapsulation, replacing the ADR 038 slice branch.\r\n *\r\n * `<label>` is content-bearing (its text is the label), so the template MUST be\r\n * `<ng-content>` — `template: ''` would discard the label text. See ADR 040 §2.\r\n *\r\n * Auto-links to its sibling control via `[htmlFor]` sourced from\r\n * `SkraFieldContext.fieldId()` — zero manual ID passing (ADR 013). The label's\r\n * error-state colour is driven by `<skra-field>[data-skra-validation=\"invalid\"]`\r\n * swapping `--skra-comp-field-label-color` through CSS variable inheritance; this\r\n * SCSS is what consumes that variable (the swap was a no-op before the binding\r\n * moved here from the slice).\r\n */\r\n@Component({\r\n selector: 'label[skraLabelFor]',\r\n standalone: true,\r\n // Content-bearing host — see ADR 040 §2.\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './label.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // The magic: auto-linking label to input via shared Context ID\r\n '[htmlFor]': 'context.fieldId()',\r\n // Referenceable id so a non-labelable control (a `role=\"radiogroup\"` host like\r\n // <skra-star-rating>, which `for`/`id` can't target) can name itself via\r\n // `aria-labelledby`. Harmless for labelable controls (they use `for`). ADR 013.\r\n '[id]': 'context.labelId()',\r\n // Required marker — reflect the field's required state so the SCSS can paint a\r\n // decorative asterisk (::after). The control already carries `aria-required`,\r\n // so the marker is purely visual (ADR 021 data-attr reflection; ADR 033 keeps\r\n // it out of the accessible name via the empty alt-text in `content`).\r\n '[attr.data-skra-required]': 'context.isRequired() ? \"\" : null',\r\n // Class hook retained for any consumer-side targeting (ADR 024 pattern).\r\n class: 'skra-label',\r\n },\r\n})\r\nexport class SkraLabel {\r\n readonly context = inject(SkraFieldContext);\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n inject,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '../field-context/field-context';\r\n\r\n/**\r\n * Hint component for supplementary field information.\r\n * Auto-receives ID from SkraFieldContext so aria-describedby on input works automatically.\r\n */\r\n@Component({\r\n selector: 'skra-hint',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './hint.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // Zero-margin reset (ADR 022) lives in hint.component.scss `:host`.\r\n // ID linked from context — input's aria-describedby points here automatically\r\n '[id]': 'context.hintId()',\r\n role: 'note',\r\n },\r\n})\r\nexport class SkraHint {\r\n readonly context = inject(SkraFieldContext);\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n inject,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '../field-context/field-context';\r\n\r\n/**\r\n * Error message atom sibling to `<skra-hint>`. Renders validation feedback\r\n * inside `<skra-field>` with its own a11y semantics: `role=\"alert\"` (which\r\n * carries an implicit `aria-live=\"assertive\"` + `aria-atomic=\"true\"`), so screen\r\n * readers announce a validation error promptly. NO explicit `aria-live` — adding\r\n * `aria-live=\"polite\"` alongside `role=\"alert\"` is contradictory (alert is\r\n * assertive by definition) and behaves inconsistently across AT. Assertive is\r\n * the WAI-ARIA APG pattern for validation errors (decision 2026-05-31, Batch 4\r\n * cleanroom review).\r\n *\r\n * Per ADR 037 (agnostic atom co-existence) — does not infer error state from\r\n * any binding strategy. Consumer renders or omits `<skra-error>` based on\r\n * their own validation source (Signal Forms `.invalid && .touched`, Reactive\r\n * Forms `ctrl.errors`, raw computed signal). The atom itself just supplies\r\n * a11y wiring + visual treatment.\r\n *\r\n * <skra-field [hasError]=\"emailHasError()\">\r\n * <label skraLabelFor>Email</label>\r\n * <input skraInput type=\"email\" />\r\n * <skra-hint>We'll never share your email.</skra-hint>\r\n * @if (emailHasError()) {\r\n * <skra-error>Please enter a valid email address.</skra-error>\r\n * }\r\n * </skra-field>\r\n *\r\n * Separate from `<skra-hint>` per SRP: hint is static helper text\r\n * (role=\"note\", neutral colour); error is dynamic validation feedback\r\n * (role=\"alert\", live region, error colour). One element per visual\r\n * responsibility — the rejected alternative (\"hint that swaps text on error\")\r\n * loaded two responsibilities into a single primitive.\r\n */\r\n@Component({\r\n selector: 'skra-error',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './error.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // Zero-margin reset (ADR 022) lives in error.component.scss `:host`.\r\n // ID linked from context — input's aria-describedby points here automatically\r\n '[id]': 'context.errorId()',\r\n // role=\"alert\" implies aria-live=\"assertive\" + aria-atomic=\"true\" — do NOT\r\n // add an explicit aria-live (contradicts the implicit assertive). Errors are\r\n // announced promptly per WAI-ARIA APG.\r\n role: 'alert',\r\n },\r\n})\r\nexport class SkraError {\r\n readonly context = inject(SkraFieldContext);\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n input,\r\n} from '@angular/core';\r\n\r\n/**\r\n * Forge marker on a native `<fieldset>` used to group related form controls\r\n * (checkbox group, radio group, or any related field cluster). Per ADR 039,\r\n * Forge ships no `<skra-radio-group>` / `<skra-checkbox-group>` component\r\n * wrappers — native `<fieldset>` + `<legend>` IS the WCAG-canonical group\r\n * idiom, and Forge stops reinventing it.\r\n *\r\n * Per ADR 040 this is a Component-on-the-native-host carrying its own\r\n * `fieldset.scss` (chrome reset + group layout) via Emulated encapsulation,\r\n * replacing the ADR 038 slice branch. `<fieldset>` is content-bearing (it holds\r\n * the grouped controls), so the template MUST be `<ng-content>` — `template: ''`\r\n * would discard the entire group. See ADR 040 §2.\r\n *\r\n * The `[disabled]` input cascades to the native `disabled` attribute, and\r\n * native `<fieldset disabled>` already disables every form control inside\r\n * (browser-native behaviour). Forge does not iterate children manually.\r\n *\r\n * Selector is opt-in (`fieldset[skraFieldset]`) so the chrome-reset rules do\r\n * not leak onto bare `<fieldset>` elements outside Forge.\r\n *\r\n * <fieldset skraFieldset [disabled]=\"form.disabled()\">\r\n * <legend skraLegend>Send notifications via</legend>\r\n * <!-- skra-field children with checkboxes -->\r\n * <skra-error *ngIf=\"form.channels().length === 0\">Choose at least one</skra-error>\r\n * </fieldset>\r\n *\r\n * `role=\"group\"` is the explicit ARIA role: while the browser default for\r\n * `<fieldset>` is already group semantics for most AT, declaring it explicitly\r\n * is friendlier to assistive tech that may have idiosyncratic handling.\r\n *\r\n * Native `disabled` is sufficient — `aria-disabled` is NOT set per\r\n * native-attr-first doctrine (memory `feedback_native_attr_first.md`). The\r\n * `data-skra-disabled` reflection drives the visual dimming in `fieldset.scss`.\r\n */\r\n@Component({\r\n selector: 'fieldset[skraFieldset]',\r\n standalone: true,\r\n // Content-bearing host — see ADR 040 §2.\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './fieldset.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'group',\r\n '[attr.disabled]': 'disabled() ? \"\" : null',\r\n '[attr.data-skra-disabled]': 'disabled() ? \"\" : null',\r\n },\r\n})\r\nexport class SkraFieldset {\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\n\r\n/**\r\n * `legend[skraLegend]` — visible group label for `<fieldset skraFieldset>`.\r\n * Per ADR 040 this is a Component-on-the-native-host carrying its own\r\n * `legend.scss` (chrome reset + typography role binding per ADR 036) via Emulated\r\n * encapsulation, replacing the ADR 038 slice branch.\r\n *\r\n * `<legend>` is content-bearing (its text is the group label), so the template\r\n * MUST be `<ng-content>` — `template: ''` would discard the label. See ADR 040 §2.\r\n * No host bindings, no inputs, no DI — purely a styled marker.\r\n *\r\n * <fieldset skraFieldset>\r\n * <legend skraLegend>Account preferences</legend>\r\n * ...\r\n * </fieldset>\r\n *\r\n * HTML requires `<legend>` to be the FIRST child of `<fieldset>` for native\r\n * group-label semantics. The browser HTML parser auto-corrects misplaced\r\n * legends (re-parents to fieldset), but Forge documents the canonical form.\r\n */\r\n@Component({\r\n selector: 'legend[skraLegend]',\r\n standalone: true,\r\n // Content-bearing host — see ADR 040 §2.\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './legend.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n})\r\nexport class SkraLegend {}\r\n","// Public API for @skra/ui/field — the field-family (ADR 013 contextual a11y).\r\nexport * from './lib/id-generator/id-generator.service';\r\nexport * from './lib/field-context/field-context';\r\nexport * from './lib/field/field.component';\r\nexport * from './lib/label/label';\r\nexport * from './lib/hint/hint.component';\r\nexport * from './lib/error/error.component';\r\nexport * from './lib/fieldset/fieldset';\r\nexport * from './lib/fieldset/legend';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skra-ui-field.mjs","sources":["../../../../libs/ui/field/src/lib/id-generator/id-generator.service.ts","../../../../libs/ui/field/src/lib/field-context/field-context.ts","../../../../libs/ui/field/src/lib/field/field.component.ts","../../../../libs/ui/field/src/lib/label/label.ts","../../../../libs/ui/field/src/lib/hint/hint.component.ts","../../../../libs/ui/field/src/lib/error/error.component.ts","../../../../libs/ui/field/src/lib/fieldset/fieldset.ts","../../../../libs/ui/field/src/lib/fieldset/legend.ts","../../../../libs/ui/field/src/index.ts","../../../../libs/ui/field/src/skra-ui-field.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\r\n\r\n/**\r\n * Root-level service generating unique, short IDs for form elements.\r\n * Implements ADR 013 — deterministic IDs without bloaty UUID libraries.\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class IdGeneratorService {\r\n private counter = 0;\r\n\r\n nextId(prefix = 'fg'): string {\r\n return `${prefix}-${++this.counter}`;\r\n }\r\n}\r\n","import { Injectable, signal, computed } from '@angular/core';\r\n\r\n/**\r\n * DI Context service provided per SkraField instance.\r\n * Acts as the synchronization bus between Field, Input, Label, Hint, and Error.\r\n * Implements ADR 013: Signal-based Contextual Interaction.\r\n */\r\n@Injectable()\r\nexport class SkraFieldContext {\r\n readonly fieldId = signal<string>('');\r\n readonly hasError = signal<boolean>(false);\r\n readonly isDisabled = signal<boolean>(false);\r\n readonly isRequired = signal<boolean>(false);\r\n readonly isReadonly = signal<boolean>(false);\r\n\r\n // Derived IDs for aria-describedby linkage\r\n readonly hintId = computed(() => `${this.fieldId()}-hint`);\r\n readonly errorId = computed(() => `${this.fieldId()}-error`);\r\n\r\n // Derived label ID. Labelable controls (input/checkbox/radio) associate via the\r\n // native `for`/`id` pair, so they never needed a referenceable label id. A\r\n // `role=\"radiogroup\"` host (<skra-star-rating>) is NOT labelable by `for`, so it\r\n // must name itself via `aria-labelledby` → the label needs an id. This is the third\r\n // derived id alongside hintId/errorId — an id, never a value (ADR 013 §3.6; the\r\n // context carries id + derived state only). Set on `label[skraLabelFor]`.\r\n readonly labelId = computed(() => `${this.fieldId()}-label`);\r\n\r\n // Combined aria-describedby tokens for the input/textarea host.\r\n // Both ids are always emitted — when <skra-hint> or <skra-error> is not\r\n // rendered, the matching DOM node is absent and browsers / screen readers\r\n // gracefully ignore the dangling reference. Simpler than tracking presence\r\n // via contentChild queries from the directive (which has no template).\r\n readonly describedByIds = computed(\r\n () => `${this.hintId()} ${this.errorId()}`,\r\n );\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n OnInit,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n effect,\r\n inject,\r\n input,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '../field-context/field-context';\r\nimport { IdGeneratorService } from '../id-generator/id-generator.service';\r\n\r\n@Component({\r\n selector: 'skra-field',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './field.component.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n // KEY: provides a new SkraFieldContext instance per field — isolation guaranteed\r\n providers: [SkraFieldContext],\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021). The layout reset (margin) +\r\n // display:flex live in field.component.scss `:host` (ADR 022) — host-metadata\r\n // bare keys (margin, display) render as junk attributes with no styling effect.\r\n // Validation state (ADR 027) — canonical `data-skra-validation=\"invalid\"`,\r\n // NOT the forbidden `data-skra-has-error` (migrated 2026-05-31 per ADR 027\r\n // §3.6 / state-surface-catalog). The control's `aria-invalid` lives on the\r\n // inner <input skraInput> (ADR 013), not on this group host.\r\n '[attr.data-skra-validation]': 'context.hasError() ? \"invalid\" : null',\r\n '[attr.data-skra-disabled]': 'context.isDisabled() ? \"\" : null',\r\n '[attr.data-skra-required]': 'context.isRequired() ? \"\" : null',\r\n '[attr.data-skra-readonly]': 'context.isReadonly() ? \"\" : null',\r\n\r\n // A11y: role=\"group\" groups label+input+hint semantically for screen readers\r\n role: 'group',\r\n },\r\n})\r\nexport class SkraField implements OnInit {\r\n private readonly idGen = inject(IdGeneratorService);\r\n readonly context = inject(SkraFieldContext);\r\n\r\n readonly fieldId = input<string | null>(null);\r\n readonly readonly = input(false, { transform: booleanAttribute });\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n readonly required = input(false, { transform: booleanAttribute });\r\n readonly hasError = input(false, { transform: booleanAttribute });\r\n\r\n constructor() {\r\n // Reactive sync — state inputs propagate to SkraFieldContext on every\r\n // change (not just on init). Replaces the previous ngOnInit-only pattern\r\n // which caused late input changes to silently desync from the context\r\n // (and from sibling atoms reading the context). Matches Checkbox's\r\n // effect() pattern for indeterminate property sync.\r\n effect(() => {\r\n this.context.isReadonly.set(this.readonly());\r\n this.context.isDisabled.set(this.disabled());\r\n this.context.isRequired.set(this.required());\r\n this.context.hasError.set(this.hasError());\r\n });\r\n }\r\n\r\n // fieldId is one-shot — assigned once on init, never changes thereafter\r\n // (a field's identity attribute should be stable for the field's lifetime).\r\n ngOnInit(): void {\r\n this.context.fieldId.set(this.fieldId() ?? this.idGen.nextId('fg'));\r\n }\r\n}\r\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '../field-context/field-context';\n\n/**\n * `label[skraLabelFor]` — form-control label atom. Per ADR 040 this is a\n * Component-on-the-native-host carrying its own `label.scss` (typography + colour\n * + cursor) via Emulated encapsulation, replacing the ADR 038 slice branch.\n *\n * `<label>` is content-bearing (its text is the label), so the template MUST be\n * `<ng-content>` — `template: ''` would discard the label text. See ADR 040 §2.\n *\n * Auto-links to its sibling control via `[htmlFor]` sourced from\n * `SkraFieldContext.fieldId()` — zero manual ID passing (ADR 013). The label's\n * error-state colour is driven by `<skra-field>[data-skra-validation=\"invalid\"]`\n * swapping `--skra-comp-field-label-color` through CSS variable inheritance; this\n * SCSS is what consumes that variable (the swap was a no-op before the binding\n * moved here from the slice).\n */\n@Component({\n selector: 'label[skraLabelFor]',\n standalone: true,\n // Content-bearing host — see ADR 040 §2.\n template: '<ng-content></ng-content>',\n styleUrl: './label.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // The magic: auto-linking label to input via shared Context ID. Bound as an\n // ATTRIBUTE, not the `htmlFor` property — with no field context the property\n // form would stringify `undefined` into `for=\"undefined\"`.\n '[attr.for]': 'context?.fieldId() ?? null',\n // Referenceable id so a non-labelable control (a `role=\"radiogroup\"` host like\n // <skra-star-rating>, which `for`/`id` can't target) can name itself via\n // `aria-labelledby`. Harmless for labelable controls (they use `for`). ADR 013.\n '[attr.id]': 'context?.labelId() ?? null',\n // Required marker — reflect the field's required state so the SCSS can paint a\n // decorative asterisk (::after). The control already carries `aria-required`,\n // so the marker is purely visual (ADR 021 data-attr reflection; ADR 033 keeps\n // it out of the accessible name via the empty alt-text in `content`).\n '[attr.data-skra-required]': 'context?.isRequired() ? \"\" : null',\n // Class hook retained for any consumer-side targeting (ADR 024 pattern).\n class: 'skra-label',\n },\n})\nexport class SkraLabel {\n // Optional per ADR 013 §3.7 — outside `<skra-field>` the label still carries the\n // skin and the consumer owns association (a wrapping `<label>`, or a hand-written\n // `for`). Mandatory injection would crash the app for a styling-only use.\n readonly context = inject(SkraFieldContext, { optional: true });\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '../field-context/field-context';\n\n/**\n * Hint component for supplementary field information.\n * Auto-receives ID from SkraFieldContext so aria-describedby on input works automatically.\n */\n@Component({\n selector: 'skra-hint',\n standalone: true,\n template: '<ng-content></ng-content>',\n styleUrl: './hint.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Zero-margin reset (ADR 022) lives in hint.component.scss `:host`.\n // ID linked from context — input's aria-describedby points here automatically\n '[attr.id]': 'context?.hintId() ?? null',\n role: 'note',\n },\n})\nexport class SkraHint {\n // Optional per ADR 013 §3.7 — mirrors SkraError. Outside `<skra-field>` it\n // publishes no id and is plain styled helper text the consumer associates itself.\n readonly context = inject(SkraFieldContext, { optional: true });\n}\n","import {\n ChangeDetectionStrategy,\n Component,\n ViewEncapsulation,\n inject,\n} from '@angular/core';\nimport { SkraFieldContext } from '../field-context/field-context';\n\n/**\n * Error message atom sibling to `<skra-hint>`. Renders validation feedback\n * inside `<skra-field>` with its own a11y semantics: `role=\"alert\"` (which\n * carries an implicit `aria-live=\"assertive\"` + `aria-atomic=\"true\"`), so screen\n * readers announce a validation error promptly. NO explicit `aria-live` — adding\n * `aria-live=\"polite\"` alongside `role=\"alert\"` is contradictory (alert is\n * assertive by definition) and behaves inconsistently across AT. Assertive is\n * the WAI-ARIA APG pattern for validation errors (decision 2026-05-31, Batch 4\n * cleanroom review).\n *\n * Per ADR 037 (agnostic atom co-existence) — does not infer error state from\n * any binding strategy. Consumer renders or omits `<skra-error>` based on\n * their own validation source (Signal Forms `.invalid && .touched`, Reactive\n * Forms `ctrl.errors`, raw computed signal). The atom itself just supplies\n * a11y wiring + visual treatment.\n *\n * <skra-field [hasError]=\"emailHasError()\">\n * <label skraLabelFor>Email</label>\n * <input skraInput type=\"email\" />\n * <skra-hint>We'll never share your email.</skra-hint>\n * @if (emailHasError()) {\n * <skra-error>Please enter a valid email address.</skra-error>\n * }\n * </skra-field>\n *\n * Separate from `<skra-hint>` per SRP: hint is static helper text\n * (role=\"note\", neutral colour); error is dynamic validation feedback\n * (role=\"alert\", live region, error colour). One element per visual\n * responsibility — the rejected alternative (\"hint that swaps text on error\")\n * loaded two responsibilities into a single primitive.\n */\n@Component({\n selector: 'skra-error',\n standalone: true,\n template: '<ng-content></ng-content>',\n styleUrl: './error.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Zero-margin reset (ADR 022) lives in error.component.scss `:host`.\n // ID linked from context — input's aria-describedby points here automatically\n '[attr.id]': 'context?.errorId() ?? null',\n // role=\"alert\" implies aria-live=\"assertive\" + aria-atomic=\"true\" — do NOT\n // add an explicit aria-live (contradicts the implicit assertive). Errors are\n // announced promptly per WAI-ARIA APG.\n role: 'alert',\n },\n})\nexport class SkraError {\n // Optional per ADR 013 §3.7. A GROUP-level error is a first-class pattern:\n // `<skra-error>` sits as a direct child of `<fieldset skraFieldset>`, outside any\n // `<skra-field>`, to carry one message for a radio/checkbox group (see the\n // Fieldset `WithGroupError` story). It then publishes no id — nothing points at\n // it via `aria-describedby`, and `role=\"alert\"` announces it on its own.\n readonly context = inject(SkraFieldContext, { optional: true });\n}\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n input,\r\n} from '@angular/core';\r\n\r\n/**\r\n * Forge marker on a native `<fieldset>` used to group related form controls\r\n * (checkbox group, radio group, or any related field cluster). Per ADR 039,\r\n * Forge ships no `<skra-radio-group>` / `<skra-checkbox-group>` component\r\n * wrappers — native `<fieldset>` + `<legend>` IS the WCAG-canonical group\r\n * idiom, and Forge stops reinventing it.\r\n *\r\n * Per ADR 040 this is a Component-on-the-native-host carrying its own\r\n * `fieldset.scss` (chrome reset + group layout) via Emulated encapsulation,\r\n * replacing the ADR 038 slice branch. `<fieldset>` is content-bearing (it holds\r\n * the grouped controls), so the template MUST be `<ng-content>` — `template: ''`\r\n * would discard the entire group. See ADR 040 §2.\r\n *\r\n * The `[disabled]` input cascades to the native `disabled` attribute, and\r\n * native `<fieldset disabled>` already disables every form control inside\r\n * (browser-native behaviour). Forge does not iterate children manually.\r\n *\r\n * Selector is opt-in (`fieldset[skraFieldset]`) so the chrome-reset rules do\r\n * not leak onto bare `<fieldset>` elements outside Forge.\r\n *\r\n * <fieldset skraFieldset [disabled]=\"form.disabled()\">\r\n * <legend skraLegend>Send notifications via</legend>\r\n * <!-- skra-field children with checkboxes -->\r\n * <skra-error *ngIf=\"form.channels().length === 0\">Choose at least one</skra-error>\r\n * </fieldset>\r\n *\r\n * `role=\"group\"` is the explicit ARIA role: while the browser default for\r\n * `<fieldset>` is already group semantics for most AT, declaring it explicitly\r\n * is friendlier to assistive tech that may have idiosyncratic handling.\r\n *\r\n * Native `disabled` is sufficient — `aria-disabled` is NOT set per\r\n * native-attr-first doctrine (memory `feedback_native_attr_first.md`). The\r\n * `data-skra-disabled` reflection drives the visual dimming in `fieldset.scss`.\r\n */\r\n@Component({\r\n selector: 'fieldset[skraFieldset]',\r\n standalone: true,\r\n // Content-bearing host — see ADR 040 §2.\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './fieldset.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n role: 'group',\r\n '[attr.disabled]': 'disabled() ? \"\" : null',\r\n '[attr.data-skra-disabled]': 'disabled() ? \"\" : null',\r\n },\r\n})\r\nexport class SkraFieldset {\r\n readonly disabled = input(false, { transform: booleanAttribute });\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n} from '@angular/core';\r\n\r\n/**\r\n * `legend[skraLegend]` — visible group label for `<fieldset skraFieldset>`.\r\n * Per ADR 040 this is a Component-on-the-native-host carrying its own\r\n * `legend.scss` (chrome reset + typography role binding per ADR 036) via Emulated\r\n * encapsulation, replacing the ADR 038 slice branch.\r\n *\r\n * `<legend>` is content-bearing (its text is the group label), so the template\r\n * MUST be `<ng-content>` — `template: ''` would discard the label. See ADR 040 §2.\r\n * No host bindings, no inputs, no DI — purely a styled marker.\r\n *\r\n * <fieldset skraFieldset>\r\n * <legend skraLegend>Account preferences</legend>\r\n * ...\r\n * </fieldset>\r\n *\r\n * HTML requires `<legend>` to be the FIRST child of `<fieldset>` for native\r\n * group-label semantics. The browser HTML parser auto-corrects misplaced\r\n * legends (re-parents to fieldset), but Forge documents the canonical form.\r\n */\r\n@Component({\r\n selector: 'legend[skraLegend]',\r\n standalone: true,\r\n // Content-bearing host — see ADR 040 §2.\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './legend.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n})\r\nexport class SkraLegend {}\r\n","// Public API for @skra/ui/field — the field-family (ADR 013 contextual a11y).\r\nexport * from './lib/id-generator/id-generator.service';\r\nexport * from './lib/field-context/field-context';\r\nexport * from './lib/field/field.component';\r\nexport * from './lib/label/label';\r\nexport * from './lib/hint/hint.component';\r\nexport * from './lib/error/error.component';\r\nexport * from './lib/fieldset/fieldset';\r\nexport * from './lib/fieldset/legend';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -123,9 +123,48 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
123
123
  }, styles: [":host{display:grid;margin:0;box-sizing:border-box}:host[data-skra-min=sm]{--skra-comp-grid-track-min: var(--skra-comp-grid-min-sm)}:host[data-skra-min=md]{--skra-comp-grid-track-min: var(--skra-comp-grid-min-md)}:host[data-skra-min=lg]{--skra-comp-grid-track-min: var(--skra-comp-grid-min-lg)}:host[data-skra-columns=\"1\"]{grid-template-columns:repeat(1,minmax(0,1fr))}:host[data-skra-columns=\"2\"]{grid-template-columns:repeat(2,minmax(0,1fr))}:host[data-skra-columns=\"3\"]{grid-template-columns:repeat(3,minmax(0,1fr))}:host[data-skra-columns=\"4\"]{grid-template-columns:repeat(4,minmax(0,1fr))}:host[data-skra-columns=\"5\"]{grid-template-columns:repeat(5,minmax(0,1fr))}:host[data-skra-columns=\"6\"]{grid-template-columns:repeat(6,minmax(0,1fr))}:host[data-skra-columns=auto-fit]{grid-template-columns:repeat(auto-fit,minmax(var(--skra-comp-grid-track-min),1fr))}:host[data-skra-columns=auto-fill]{grid-template-columns:repeat(auto-fill,minmax(var(--skra-comp-grid-track-min),1fr))}:host[data-skra-gap=none]{gap:0}:host[data-skra-gap=sm]{gap:var(--skra-comp-grid-gap-sm)}:host[data-skra-gap=md]{gap:var(--skra-comp-grid-gap-md)}:host[data-skra-gap=lg]{gap:var(--skra-comp-grid-gap-lg)}:host[data-skra-flow=row]{grid-auto-flow:row}:host[data-skra-flow=column]{grid-auto-flow:column}:host[data-skra-flow=dense]{grid-auto-flow:row dense}:host[data-skra-align=start]{align-items:start}:host[data-skra-align=center]{align-items:center}:host[data-skra-align=end]{align-items:end}:host[data-skra-align=stretch]{align-items:stretch}:host[data-skra-justify-items=start]{justify-items:start}:host[data-skra-justify-items=center]{justify-items:center}:host[data-skra-justify-items=end]{justify-items:end}:host[data-skra-justify-items=stretch]{justify-items:stretch}:host(ul),:host(ol),:host(menu){list-style:none;padding-inline-start:0}\n"] }]
124
124
  }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: false }] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], gap: [{ type: i0.Input, args: [{ isSignal: true, alias: "gap", required: false }] }], flow: [{ type: i0.Input, args: [{ isSignal: true, alias: "flow", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], justifyItems: [{ type: i0.Input, args: [{ isSignal: true, alias: "justifyItems", required: false }] }] } });
125
125
 
126
+ /**
127
+ * SkraSurface — the painted container primitive (ADR 0053), Box's painting sibling.
128
+ *
129
+ * Component-on-native-host: layers onto a generic flow/sectioning container via the
130
+ * bounded host allowlist below — NEVER a `<skra-surface>` custom element, and never
131
+ * an interactive host (ADR 0055 R3.1: `a[skraSurface]` / `button[skraSurface]` are
132
+ * unsupported). "Card", "Panel" and "Tile" are consumer compositions of Surface +
133
+ * `[skraStack]`/`[skraBox]` + a heading — not Skra components (ADR 0053 rule 1).
134
+ *
135
+ * **State-reading doctrine (ADR 0055).** Surface is a READER of state, never an
136
+ * OWNER of state. It exposes no `interactive`/`hoverable`/`selected`/`elevation`
137
+ * input and emits no `role`/`tabindex`/`aria-*`. Focus and selection are READ from
138
+ * the markup the consumer authored (see surface.scss) — which is why an
139
+ * informational card gets no interactive paint with zero API, and why a selected
140
+ * card can never disagree with what assistive technology announces.
141
+ *
142
+ * Zero baked semantics: sectioning role and accessible name are 100% consumer-owned
143
+ * (ADR 0053 rule 6). No `container-type` in v1 (ADR 0055 R7.1).
144
+ */
145
+ class SkraSurface {
146
+ /**
147
+ * Semantic padding preset, reusing Box's enum for cross-atom consistency
148
+ * (ADR 0053 rule 4). Defaults to `md` rather than Box's `none` — Box is
149
+ * spacing-neutral by construction, a painted container is not (ADR 0055 R1).
150
+ */
151
+ padding = input('md', /* @ts-ignore */
152
+ ...(ngDevMode ? [{ debugName: "padding" }] : /* istanbul ignore next */ []));
153
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSurface, deps: [], target: i0.ɵɵFactoryTarget.Component });
154
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.1", type: SkraSurface, isStandalone: true, selector: "div[skraSurface], section[skraSurface], article[skraSurface], main[skraSurface], nav[skraSurface], aside[skraSurface], header[skraSurface], footer[skraSurface], figure[skraSurface]", inputs: { padding: { classPropertyName: "padding", publicName: "padding", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.data-skra-padding": "padding()" } }, ngImport: i0, template: '<ng-content></ng-content>', isInline: true, styles: [":host{display:block;margin:0;box-sizing:border-box;background:var(--skra-comp-surface-background);color:var(--skra-comp-surface-foreground);border-color:var(--skra-comp-surface-border-color);border-width:var(--skra-comp-surface-border-width);border-style:var(--skra-comp-surface-border-style);border-radius:var(--skra-comp-surface-radius);box-shadow:var(--skra-comp-surface-shadow);padding-block:var(--skra-comp-surface-padding-block);padding-inline:var(--skra-comp-surface-padding-inline);transition:background-color var(--skra-comp-surface-motion-duration) var(--skra-comp-surface-motion-easing),border-color var(--skra-comp-surface-motion-duration) var(--skra-comp-surface-motion-easing)}:host[data-skra-padding=none]{padding-block:0;padding-inline:0}:host[data-skra-padding=sm]{padding-block:var(--skra-comp-surface-padding-block-sm);padding-inline:var(--skra-comp-surface-padding-inline-sm)}:host[data-skra-padding=md]{padding-block:var(--skra-comp-surface-padding-block);padding-inline:var(--skra-comp-surface-padding-inline)}:host[data-skra-padding=lg]{padding-block:var(--skra-comp-surface-padding-block-lg);padding-inline:var(--skra-comp-surface-padding-inline-lg)}:host([aria-current]),:host([aria-selected=true]){background:var(--skra-comp-surface-background-selected);border-color:var(--skra-comp-surface-border-color-selected);border-width:var(--skra-comp-surface-border-width-selected)}:host([aria-current=false]),:host([aria-selected=false]){background:var(--skra-comp-surface-background);border-color:var(--skra-comp-surface-border-color);border-width:var(--skra-comp-surface-border-width)}:host(:focus-visible){outline:var(--skra-comp-surface-focus-ring-width) solid var(--skra-comp-surface-focus-ring-color);outline-offset:var(--skra-comp-surface-focus-ring-width)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
155
+ }
156
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraSurface, decorators: [{
157
+ type: Component,
158
+ args: [{ selector: 'div[skraSurface], section[skraSurface], article[skraSurface], main[skraSurface], nav[skraSurface], aside[skraSurface], header[skraSurface], footer[skraSurface], figure[skraSurface]', standalone: true, template: '<ng-content></ng-content>', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.Emulated, host: {
159
+ // CSP-Safe State Reflection (ADR 021) — NO inline styles. This is the ONLY
160
+ // host attribute Surface emits (ADR 0055 R2): no role, no tabindex, no aria-*.
161
+ '[attr.data-skra-padding]': 'padding()',
162
+ }, styles: [":host{display:block;margin:0;box-sizing:border-box;background:var(--skra-comp-surface-background);color:var(--skra-comp-surface-foreground);border-color:var(--skra-comp-surface-border-color);border-width:var(--skra-comp-surface-border-width);border-style:var(--skra-comp-surface-border-style);border-radius:var(--skra-comp-surface-radius);box-shadow:var(--skra-comp-surface-shadow);padding-block:var(--skra-comp-surface-padding-block);padding-inline:var(--skra-comp-surface-padding-inline);transition:background-color var(--skra-comp-surface-motion-duration) var(--skra-comp-surface-motion-easing),border-color var(--skra-comp-surface-motion-duration) var(--skra-comp-surface-motion-easing)}:host[data-skra-padding=none]{padding-block:0;padding-inline:0}:host[data-skra-padding=sm]{padding-block:var(--skra-comp-surface-padding-block-sm);padding-inline:var(--skra-comp-surface-padding-inline-sm)}:host[data-skra-padding=md]{padding-block:var(--skra-comp-surface-padding-block);padding-inline:var(--skra-comp-surface-padding-inline)}:host[data-skra-padding=lg]{padding-block:var(--skra-comp-surface-padding-block-lg);padding-inline:var(--skra-comp-surface-padding-inline-lg)}:host([aria-current]),:host([aria-selected=true]){background:var(--skra-comp-surface-background-selected);border-color:var(--skra-comp-surface-border-color-selected);border-width:var(--skra-comp-surface-border-width-selected)}:host([aria-current=false]),:host([aria-selected=false]){background:var(--skra-comp-surface-background);border-color:var(--skra-comp-surface-border-color);border-width:var(--skra-comp-surface-border-width)}:host(:focus-visible){outline:var(--skra-comp-surface-focus-ring-width) solid var(--skra-comp-surface-focus-ring-color);outline-offset:var(--skra-comp-surface-focus-ring-width)}@media(prefers-reduced-motion:reduce){:host{transition:none}}\n"] }]
163
+ }], propDecorators: { padding: [{ type: i0.Input, args: [{ isSignal: true, alias: "padding", required: false }] }] } });
164
+
126
165
  /**
127
166
  * Generated bundle index. Do not edit.
128
167
  */
129
168
 
130
- export { SkraBox, SkraGrid, SkraStack };
169
+ export { SkraBox, SkraGrid, SkraStack, SkraSurface };
131
170
  //# sourceMappingURL=skra-ui-layout.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-layout.mjs","sources":["../../../../libs/ui/layout/src/lib/box/box.ts","../../../../libs/ui/layout/src/lib/stack/stack.ts","../../../../libs/ui/layout/src/lib/grid/grid.ts","../../../../libs/ui/layout/src/skra-ui-layout.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type BoxPadding = 'none' | 'sm' | 'md' | 'lg';\r\nexport type BoxDisplay = 'block' | 'inline-block' | 'flex';\r\n\r\n/**\r\n * SkraBox — semantically-neutral spacing/padding primitive (ADR 041).\r\n *\r\n * Component-on-native-host: layers onto a generic flow/sectioning container via\r\n * the bounded host allowlist below — NEVER a `<skra-box>` custom element\r\n * (ADR 012 §3.1 / ADR 041). Box does NOT arrange children, so list hosts\r\n * (`ul`/`ol`/`menu`) are intentionally excluded from its allowlist.\r\n *\r\n * Box is a pure spacing primitive: it MUST NOT establish a container-query\r\n * context (`container-type`/`container-name`) — that is an app-level concern\r\n * (ADR 016 §3.3, amended by ADR 041).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraBox], section[skraBox], article[skraBox], main[skraBox], nav[skraBox], aside[skraBox], header[skraBox], footer[skraBox], form[skraBox], figure[skraBox]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './box.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021) — NO inline styles! The layout reset\r\n // (margin/box-sizing) + figure UA-margin normalization live in box.scss\r\n // `:host` (ADR 022 / ADR 041 Host Normalization Contract); host-metadata\r\n // bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-padding]': 'padding()',\r\n '[attr.data-skra-display]': 'display()',\r\n },\r\n})\r\nexport class SkraBox {\r\n readonly padding = input<BoxPadding>('none');\r\n readonly display = input<BoxDisplay>('block');\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type StackDirection = 'row' | 'column';\r\nexport type StackGap = 'none' | 'sm' | 'md' | 'lg';\r\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\r\nexport type StackJustify = 'start' | 'center' | 'end' | 'between' | 'around';\r\n\r\n/**\r\n * SkraStack — flex layout primitive that arranges its children (ADR 041).\r\n *\r\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\r\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\r\n * is normalized in stack.scss per the Host Normalization Contract. List markers\r\n * are restorable without `!important` via a direct `li {}` rule (a direct\r\n * declaration beats the inherited `list-style: none`).\r\n *\r\n * Stack consumes `@container`; it MUST NOT establish a container-query context\r\n * (ADR 016 §3.3, amended by ADR 041).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraStack], section[skraStack], article[skraStack], main[skraStack], nav[skraStack], aside[skraStack], header[skraStack], footer[skraStack], form[skraStack], figure[skraStack], ul[skraStack], ol[skraStack], menu[skraStack]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './stack.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The\r\n // layout reset (margin/box-sizing) + list/UA normalization live in\r\n // stack.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\r\n // host-metadata bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-direction]': 'direction()',\r\n '[attr.data-skra-gap]': 'gap()',\r\n '[attr.data-skra-align]': 'align()',\r\n '[attr.data-skra-justify]': 'justify()',\r\n '[attr.data-skra-wrap]': 'wrap() ? \"\" : null',\r\n },\r\n})\r\nexport class SkraStack {\r\n readonly direction = input<StackDirection>('column');\r\n readonly gap = input<StackGap>('md');\r\n readonly align = input<StackAlign>('stretch');\r\n readonly justify = input<StackJustify>('start');\r\n readonly wrap = input(false, { transform: booleanAttribute });\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type GridColumns =\r\n | '1'\r\n | '2'\r\n | '3'\r\n | '4'\r\n | '5'\r\n | '6'\r\n | 'auto-fit'\r\n | 'auto-fill';\r\nexport type GridMin = 'sm' | 'md' | 'lg';\r\nexport type GridGap = 'none' | 'sm' | 'md' | 'lg';\r\nexport type GridFlow = 'row' | 'column' | 'dense';\r\nexport type GridAlign = 'start' | 'center' | 'end' | 'stretch';\r\n\r\n/**\r\n * SkraGrid — 2D layout primitive that arranges its children in a CSS Grid\r\n * (ADR 041, scope O-3). The bucket-only companion to Stack (1D) and Box (spacing).\r\n *\r\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\r\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\r\n * is normalized in grid.scss per the Host Normalization Contract.\r\n *\r\n * Bucket-only by design: every axis is an enumerated input reflected as a\r\n * `data-skra-*` attribute → token. Arbitrary track lists, `grid-template-areas`,\r\n * named lines and per-item placement are OUT of scope (bespoke = native CSS) —\r\n * exposing them would force an `[style.*]` host binding (ADR 021 violation).\r\n *\r\n * Responsiveness: `columns=\"auto-fit\"` (default) + `min` produce an intrinsically\r\n * responsive card grid via `repeat(auto-fit, minmax(var(--min), 1fr))` — column\r\n * count tracks available width with NO media/container queries. Grid consumes\r\n * `@container`; it MUST NOT establish a container-query context (ADR 041 §3.3).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraGrid], section[skraGrid], article[skraGrid], main[skraGrid], nav[skraGrid], aside[skraGrid], header[skraGrid], footer[skraGrid], form[skraGrid], figure[skraGrid], ul[skraGrid], ol[skraGrid], menu[skraGrid]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './grid.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The layout\r\n // reset (margin/box-sizing/display:grid) + list/UA normalization live in\r\n // grid.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\r\n // host-metadata bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-columns]': 'columns()',\r\n '[attr.data-skra-min]': 'min()',\r\n '[attr.data-skra-gap]': 'gap()',\r\n '[attr.data-skra-flow]': 'flow()',\r\n '[attr.data-skra-align]': 'align()',\r\n '[attr.data-skra-justify-items]': 'justifyItems()',\r\n },\r\n})\r\nexport class SkraGrid {\r\n readonly columns = input<GridColumns>('auto-fit');\r\n readonly min = input<GridMin>('md');\r\n readonly gap = input<GridGap>('md');\r\n readonly flow = input<GridFlow>('row');\r\n readonly align = input<GridAlign>('stretch');\r\n readonly justifyItems = input<GridAlign>('stretch');\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"skra-ui-layout.mjs","sources":["../../../../libs/ui/layout/src/lib/box/box.ts","../../../../libs/ui/layout/src/lib/stack/stack.ts","../../../../libs/ui/layout/src/lib/grid/grid.ts","../../../../libs/ui/layout/src/lib/surface/surface.ts","../../../../libs/ui/layout/src/skra-ui-layout.ts"],"sourcesContent":["import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type BoxPadding = 'none' | 'sm' | 'md' | 'lg';\r\nexport type BoxDisplay = 'block' | 'inline-block' | 'flex';\r\n\r\n/**\r\n * SkraBox — semantically-neutral spacing/padding primitive (ADR 041).\r\n *\r\n * Component-on-native-host: layers onto a generic flow/sectioning container via\r\n * the bounded host allowlist below — NEVER a `<skra-box>` custom element\r\n * (ADR 012 §3.1 / ADR 041). Box does NOT arrange children, so list hosts\r\n * (`ul`/`ol`/`menu`) are intentionally excluded from its allowlist.\r\n *\r\n * Box is a pure spacing primitive: it MUST NOT establish a container-query\r\n * context (`container-type`/`container-name`) — that is an app-level concern\r\n * (ADR 016 §3.3, amended by ADR 041).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraBox], section[skraBox], article[skraBox], main[skraBox], nav[skraBox], aside[skraBox], header[skraBox], footer[skraBox], form[skraBox], figure[skraBox]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './box.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021) — NO inline styles! The layout reset\r\n // (margin/box-sizing) + figure UA-margin normalization live in box.scss\r\n // `:host` (ADR 022 / ADR 041 Host Normalization Contract); host-metadata\r\n // bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-padding]': 'padding()',\r\n '[attr.data-skra-display]': 'display()',\r\n },\r\n})\r\nexport class SkraBox {\r\n readonly padding = input<BoxPadding>('none');\r\n readonly display = input<BoxDisplay>('block');\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n booleanAttribute,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type StackDirection = 'row' | 'column';\r\nexport type StackGap = 'none' | 'sm' | 'md' | 'lg';\r\nexport type StackAlign = 'start' | 'center' | 'end' | 'stretch';\r\nexport type StackJustify = 'start' | 'center' | 'end' | 'between' | 'around';\r\n\r\n/**\r\n * SkraStack — flex layout primitive that arranges its children (ADR 041).\r\n *\r\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\r\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\r\n * is normalized in stack.scss per the Host Normalization Contract. List markers\r\n * are restorable without `!important` via a direct `li {}` rule (a direct\r\n * declaration beats the inherited `list-style: none`).\r\n *\r\n * Stack consumes `@container`; it MUST NOT establish a container-query context\r\n * (ADR 016 §3.3, amended by ADR 041).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraStack], section[skraStack], article[skraStack], main[skraStack], nav[skraStack], aside[skraStack], header[skraStack], footer[skraStack], form[skraStack], figure[skraStack], ul[skraStack], ol[skraStack], menu[skraStack]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './stack.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The\r\n // layout reset (margin/box-sizing) + list/UA normalization live in\r\n // stack.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\r\n // host-metadata bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-direction]': 'direction()',\r\n '[attr.data-skra-gap]': 'gap()',\r\n '[attr.data-skra-align]': 'align()',\r\n '[attr.data-skra-justify]': 'justify()',\r\n '[attr.data-skra-wrap]': 'wrap() ? \"\" : null',\r\n },\r\n})\r\nexport class SkraStack {\r\n readonly direction = input<StackDirection>('column');\r\n readonly gap = input<StackGap>('md');\r\n readonly align = input<StackAlign>('stretch');\r\n readonly justify = input<StackJustify>('start');\r\n readonly wrap = input(false, { transform: booleanAttribute });\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type GridColumns =\r\n | '1'\r\n | '2'\r\n | '3'\r\n | '4'\r\n | '5'\r\n | '6'\r\n | 'auto-fit'\r\n | 'auto-fill';\r\nexport type GridMin = 'sm' | 'md' | 'lg';\r\nexport type GridGap = 'none' | 'sm' | 'md' | 'lg';\r\nexport type GridFlow = 'row' | 'column' | 'dense';\r\nexport type GridAlign = 'start' | 'center' | 'end' | 'stretch';\r\n\r\n/**\r\n * SkraGrid — 2D layout primitive that arranges its children in a CSS Grid\r\n * (ADR 041, scope O-3). The bucket-only companion to Stack (1D) and Box (spacing).\r\n *\r\n * Component-on-native-host via the bounded allowlist below. As a child-arranger\r\n * it additionally accepts list hosts (`ul`/`ol`/`menu`) — their UA list styling\r\n * is normalized in grid.scss per the Host Normalization Contract.\r\n *\r\n * Bucket-only by design: every axis is an enumerated input reflected as a\r\n * `data-skra-*` attribute → token. Arbitrary track lists, `grid-template-areas`,\r\n * named lines and per-item placement are OUT of scope (bespoke = native CSS) —\r\n * exposing them would force an `[style.*]` host binding (ADR 021 violation).\r\n *\r\n * Responsiveness: `columns=\"auto-fit\"` (default) + `min` produce an intrinsically\r\n * responsive card grid via `repeat(auto-fit, minmax(var(--min), 1fr))` — column\r\n * count tracks available width with NO media/container queries. Grid consumes\r\n * `@container`; it MUST NOT establish a container-query context (ADR 041 §3.3).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraGrid], section[skraGrid], article[skraGrid], main[skraGrid], nav[skraGrid], aside[skraGrid], header[skraGrid], footer[skraGrid], form[skraGrid], figure[skraGrid], ul[skraGrid], ol[skraGrid], menu[skraGrid]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './grid.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection — only data-attributes, no [style.*]. The layout\r\n // reset (margin/box-sizing/display:grid) + list/UA normalization live in\r\n // grid.scss `:host` (ADR 022 / ADR 041 Host Normalization Contract);\r\n // host-metadata bare keys would render as junk attributes, not styles.\r\n '[attr.data-skra-columns]': 'columns()',\r\n '[attr.data-skra-min]': 'min()',\r\n '[attr.data-skra-gap]': 'gap()',\r\n '[attr.data-skra-flow]': 'flow()',\r\n '[attr.data-skra-align]': 'align()',\r\n '[attr.data-skra-justify-items]': 'justifyItems()',\r\n },\r\n})\r\nexport class SkraGrid {\r\n readonly columns = input<GridColumns>('auto-fit');\r\n readonly min = input<GridMin>('md');\r\n readonly gap = input<GridGap>('md');\r\n readonly flow = input<GridFlow>('row');\r\n readonly align = input<GridAlign>('stretch');\r\n readonly justifyItems = input<GridAlign>('stretch');\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n input,\r\n} from '@angular/core';\r\n\r\nexport type SurfacePadding = 'none' | 'sm' | 'md' | 'lg';\r\n\r\n/**\r\n * SkraSurface — the painted container primitive (ADR 0053), Box's painting sibling.\r\n *\r\n * Component-on-native-host: layers onto a generic flow/sectioning container via the\r\n * bounded host allowlist below — NEVER a `<skra-surface>` custom element, and never\r\n * an interactive host (ADR 0055 R3.1: `a[skraSurface]` / `button[skraSurface]` are\r\n * unsupported). \"Card\", \"Panel\" and \"Tile\" are consumer compositions of Surface +\r\n * `[skraStack]`/`[skraBox]` + a heading — not Skra components (ADR 0053 rule 1).\r\n *\r\n * **State-reading doctrine (ADR 0055).** Surface is a READER of state, never an\r\n * OWNER of state. It exposes no `interactive`/`hoverable`/`selected`/`elevation`\r\n * input and emits no `role`/`tabindex`/`aria-*`. Focus and selection are READ from\r\n * the markup the consumer authored (see surface.scss) — which is why an\r\n * informational card gets no interactive paint with zero API, and why a selected\r\n * card can never disagree with what assistive technology announces.\r\n *\r\n * Zero baked semantics: sectioning role and accessible name are 100% consumer-owned\r\n * (ADR 0053 rule 6). No `container-type` in v1 (ADR 0055 R7.1).\r\n */\r\n@Component({\r\n selector:\r\n 'div[skraSurface], section[skraSurface], article[skraSurface], main[skraSurface], nav[skraSurface], aside[skraSurface], header[skraSurface], footer[skraSurface], figure[skraSurface]',\r\n standalone: true,\r\n template: '<ng-content></ng-content>',\r\n styleUrl: './surface.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // CSP-Safe State Reflection (ADR 021) — NO inline styles. This is the ONLY\r\n // host attribute Surface emits (ADR 0055 R2): no role, no tabindex, no aria-*.\r\n '[attr.data-skra-padding]': 'padding()',\r\n },\r\n})\r\nexport class SkraSurface {\r\n /**\r\n * Semantic padding preset, reusing Box's enum for cross-atom consistency\r\n * (ADR 0053 rule 4). Defaults to `md` rather than Box's `none` — Box is\r\n * spacing-neutral by construction, a painted container is not (ADR 0055 R1).\r\n */\r\n readonly padding = input<SurfacePadding>('md');\r\n}\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skra/ui",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "license": "Apache-2.0",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -10,7 +10,7 @@
10
10
  "@angular/core": ">=22.0.0 <23.0.0",
11
11
  "@angular/common": ">=22.0.0 <23.0.0",
12
12
  "@angular/cdk": ">=22.0.0 <23.0.0",
13
- "@skra/tokens": "^0.3.0"
13
+ "@skra/tokens": "^0.4.0"
14
14
  },
15
15
  "dependencies": {
16
16
  "@floating-ui/dom": "^1.7.6",
@@ -61,7 +61,7 @@ declare class SkraField implements OnInit {
61
61
  * moved here from the slice).
62
62
  */
63
63
  declare class SkraLabel {
64
- readonly context: SkraFieldContext;
64
+ readonly context: SkraFieldContext | null;
65
65
  static ɵfac: i0.ɵɵFactoryDeclaration<SkraLabel, never>;
66
66
  static ɵcmp: i0.ɵɵComponentDeclaration<SkraLabel, "label[skraLabelFor]", never, {}, {}, never, ["*"], true, never>;
67
67
  }
@@ -71,7 +71,7 @@ declare class SkraLabel {
71
71
  * Auto-receives ID from SkraFieldContext so aria-describedby on input works automatically.
72
72
  */
73
73
  declare class SkraHint {
74
- readonly context: SkraFieldContext;
74
+ readonly context: SkraFieldContext | null;
75
75
  static ɵfac: i0.ɵɵFactoryDeclaration<SkraHint, never>;
76
76
  static ɵcmp: i0.ɵɵComponentDeclaration<SkraHint, "skra-hint", never, {}, {}, never, ["*"], true, never>;
77
77
  }
@@ -108,7 +108,7 @@ declare class SkraHint {
108
108
  * loaded two responsibilities into a single primitive.
109
109
  */
110
110
  declare class SkraError {
111
- readonly context: SkraFieldContext;
111
+ readonly context: SkraFieldContext | null;
112
112
  static ɵfac: i0.ɵɵFactoryDeclaration<SkraError, never>;
113
113
  static ɵcmp: i0.ɵɵComponentDeclaration<SkraError, "skra-error", never, {}, {}, never, ["*"], true, never>;
114
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-field.d.ts","sources":["../../../../libs/ui/field/src/lib/id-generator/id-generator.service.ts","../../../../libs/ui/field/src/lib/field-context/field-context.ts","../../../../libs/ui/field/src/lib/field/field.component.ts","../../../../libs/ui/field/src/lib/label/label.ts","../../../../libs/ui/field/src/lib/hint/hint.component.ts","../../../../libs/ui/field/src/lib/error/error.component.ts","../../../../libs/ui/field/src/lib/fieldset/fieldset.ts","../../../../libs/ui/field/src/lib/fieldset/legend.ts"],"mappings":";;;AAEA;;;AAGG;AACH,cACa,kBAAkB;;AAG7B;yCAHW,kBAAkB;6CAAlB,kBAAkB;AAM9B;;ACXD;;;;AAIG;AACH,cACa,gBAAgB;sBACXA,EAAA,CAAA,cAAA;uBACCA,EAAA,CAAA,cAAA;yBACEA,EAAA,CAAA,cAAA;yBACAA,EAAA,CAAA,cAAA;yBACAA,EAAA,CAAA,cAAA;qBAGJA,EAAA,CAAA,MAAA;sBACCA,EAAA,CAAA,MAAA;sBAQAA,EAAA,CAAA,MAAA;6BAOOA,EAAA,CAAA,MAAA;yCAxBZ,gBAAgB;6CAAhB,gBAAgB;AA2B5B;;ACtBD,cA0Ba,SAAU,YAAW,MAAM;AACtC;sBACgB,gBAAA;sBAEAA,EAAA,CAAA,WAAA;uBACCA,EAAA,CAAA,wBAAA;uBACAA,EAAA,CAAA,wBAAA;uBACAA,EAAA,CAAA,wBAAA;uBACAA,EAAA,CAAA,wBAAA;;AAkBjB;yCA1BW,SAAS;2CAAT,SAAS;AA6BrB;;AC5DD;;;;;;;;;;;;;;AAcG;AACH,cAwBa,SAAS;sBACJ,gBAAA;yCADL,SAAS;2CAAT,SAAS;AAErB;;ACzCD;;;AAGG;AACH,cAca,QAAQ;sBACH,gBAAA;yCADL,QAAQ;2CAAR,QAAQ;AAEpB;;ACpBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BG;AACH,cAiBa,SAAS;sBACJ,gBAAA;yCADL,SAAS;2CAAT,SAAS;AAErB;;AClDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;AACH,cAca,YAAY;uBACNA,EAAA,CAAA,wBAAA;yCADN,YAAY;2CAAZ,YAAY;AAExB;;ACpDD;;;;;;;;;;;;;;;;;;AAkBG;AACH,cASa,UAAU;yCAAV,UAAU;2CAAV,UAAU;AAAG;;;;","names":["_angular_core"]}
1
+ {"version":3,"file":"skra-ui-field.d.ts","sources":["../../../../libs/ui/field/src/lib/id-generator/id-generator.service.ts","../../../../libs/ui/field/src/lib/field-context/field-context.ts","../../../../libs/ui/field/src/lib/field/field.component.ts","../../../../libs/ui/field/src/lib/label/label.ts","../../../../libs/ui/field/src/lib/hint/hint.component.ts","../../../../libs/ui/field/src/lib/error/error.component.ts","../../../../libs/ui/field/src/lib/fieldset/fieldset.ts","../../../../libs/ui/field/src/lib/fieldset/legend.ts"],"mappings":";;;AAEA;;;AAGG;AACH,cACa,kBAAkB;;AAG7B;yCAHW,kBAAkB;6CAAlB,kBAAkB;AAM9B;;ACXD;;;;AAIG;AACH,cACa,gBAAgB;sBACXA,EAAA,CAAA,cAAA;uBACCA,EAAA,CAAA,cAAA;yBACEA,EAAA,CAAA,cAAA;yBACAA,EAAA,CAAA,cAAA;yBACAA,EAAA,CAAA,cAAA;qBAGJA,EAAA,CAAA,MAAA;sBACCA,EAAA,CAAA,MAAA;sBAQAA,EAAA,CAAA,MAAA;6BAOOA,EAAA,CAAA,MAAA;yCAxBZ,gBAAgB;6CAAhB,gBAAgB;AA2B5B;;ACtBD,cA0Ba,SAAU,YAAW,MAAM;AACtC;sBACgB,gBAAA;sBAEAA,EAAA,CAAA,WAAA;uBACCA,EAAA,CAAA,wBAAA;uBACAA,EAAA,CAAA,wBAAA;uBACAA,EAAA,CAAA,wBAAA;uBACAA,EAAA,CAAA,wBAAA;;AAkBjB;yCA1BW,SAAS;2CAAT,SAAS;AA6BrB;;AC5DD;;;;;;;;;;;;;;AAcG;AACH,cA0Ba,SAAS;sBAIJ,gBAAA;yCAJL,SAAS;2CAAT,SAAS;AAKrB;;AC9CD;;;AAGG;AACH,cAca,QAAQ;sBAGH,gBAAA;yCAHL,QAAQ;2CAAR,QAAQ;AAIpB;;ACtBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8BG;AACH,cAiBa,SAAS;sBAMJ,gBAAA;yCANL,SAAS;2CAAT,SAAS;AAOrB;;ACvDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCG;AACH,cAca,YAAY;uBACNA,EAAA,CAAA,wBAAA;yCADN,YAAY;2CAAZ,YAAY;AAExB;;ACpDD;;;;;;;;;;;;;;;;;;AAkBG;AACH,cASa,UAAU;yCAAV,UAAU;2CAAV,UAAU;AAAG;;;;","names":["_angular_core"]}
@@ -81,6 +81,37 @@ declare class SkraGrid {
81
81
  static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraGrid, "div[skraGrid], section[skraGrid], article[skraGrid], main[skraGrid], nav[skraGrid], aside[skraGrid], header[skraGrid], footer[skraGrid], form[skraGrid], figure[skraGrid], ul[skraGrid], ol[skraGrid], menu[skraGrid]", never, { "columns": { "alias": "columns"; "required": false; "isSignal": true; }; "min": { "alias": "min"; "required": false; "isSignal": true; }; "gap": { "alias": "gap"; "required": false; "isSignal": true; }; "flow": { "alias": "flow"; "required": false; "isSignal": true; }; "align": { "alias": "align"; "required": false; "isSignal": true; }; "justifyItems": { "alias": "justifyItems"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
82
82
  }
83
83
 
84
- export { SkraBox, SkraGrid, SkraStack };
85
- export type { BoxDisplay, BoxPadding, GridAlign, GridColumns, GridFlow, GridGap, GridMin, StackAlign, StackDirection, StackGap, StackJustify };
84
+ type SurfacePadding = 'none' | 'sm' | 'md' | 'lg';
85
+ /**
86
+ * SkraSurface — the painted container primitive (ADR 0053), Box's painting sibling.
87
+ *
88
+ * Component-on-native-host: layers onto a generic flow/sectioning container via the
89
+ * bounded host allowlist below — NEVER a `<skra-surface>` custom element, and never
90
+ * an interactive host (ADR 0055 R3.1: `a[skraSurface]` / `button[skraSurface]` are
91
+ * unsupported). "Card", "Panel" and "Tile" are consumer compositions of Surface +
92
+ * `[skraStack]`/`[skraBox]` + a heading — not Skra components (ADR 0053 rule 1).
93
+ *
94
+ * **State-reading doctrine (ADR 0055).** Surface is a READER of state, never an
95
+ * OWNER of state. It exposes no `interactive`/`hoverable`/`selected`/`elevation`
96
+ * input and emits no `role`/`tabindex`/`aria-*`. Focus and selection are READ from
97
+ * the markup the consumer authored (see surface.scss) — which is why an
98
+ * informational card gets no interactive paint with zero API, and why a selected
99
+ * card can never disagree with what assistive technology announces.
100
+ *
101
+ * Zero baked semantics: sectioning role and accessible name are 100% consumer-owned
102
+ * (ADR 0053 rule 6). No `container-type` in v1 (ADR 0055 R7.1).
103
+ */
104
+ declare class SkraSurface {
105
+ /**
106
+ * Semantic padding preset, reusing Box's enum for cross-atom consistency
107
+ * (ADR 0053 rule 4). Defaults to `md` rather than Box's `none` — Box is
108
+ * spacing-neutral by construction, a painted container is not (ADR 0055 R1).
109
+ */
110
+ readonly padding: _angular_core.InputSignal<SurfacePadding>;
111
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkraSurface, never>;
112
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraSurface, "div[skraSurface], section[skraSurface], article[skraSurface], main[skraSurface], nav[skraSurface], aside[skraSurface], header[skraSurface], footer[skraSurface], figure[skraSurface]", never, { "padding": { "alias": "padding"; "required": false; "isSignal": true; }; }, {}, never, ["*"], true, never>;
113
+ }
114
+
115
+ export { SkraBox, SkraGrid, SkraStack, SkraSurface };
116
+ export type { BoxDisplay, BoxPadding, GridAlign, GridColumns, GridFlow, GridGap, GridMin, StackAlign, StackDirection, StackGap, StackJustify, SurfacePadding };
86
117
  //# sourceMappingURL=skra-ui-layout.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-layout.d.ts","sources":["../../../../libs/ui/layout/src/lib/box/box.ts","../../../../libs/ui/layout/src/lib/stack/stack.ts","../../../../libs/ui/layout/src/lib/grid/grid.ts"],"mappings":";;AAOM,KAAM,UAAU;AAChB,KAAM,UAAU;AAEtB;;;;;;;;;;;AAWG;AACH,cAiBa,OAAO;sBACF,aAAA,CAAA,WAAA,CAAA,UAAA;sBACA,aAAA,CAAA,WAAA,CAAA,UAAA;oDAFL,OAAO;sDAAP,OAAO;AAGnB;;KClCW,cAAc;AACpB,KAAM,QAAQ;AACd,KAAM,UAAU;AAChB,KAAM,YAAY;AAExB;;;;;;;;;;;AAWG;AACH,cAoBa,SAAS;wBACF,aAAA,CAAA,WAAA,CAAA,cAAA;kBACN,aAAA,CAAA,WAAA,CAAA,QAAA;oBACE,aAAA,CAAA,WAAA,CAAA,UAAA;sBACE,aAAA,CAAA,WAAA,CAAA,YAAA;mBACH,aAAA,CAAA,wBAAA;oDALF,SAAS;sDAAT,SAAS;AAMrB;;KC5CW,WAAW;AASjB,KAAM,OAAO;AACb,KAAM,OAAO;AACb,KAAM,QAAQ;AACd,KAAM,SAAS;AAErB;;;;;;;;;;;;;;;;;AAiBG;AACH,cAqBa,QAAQ;sBACH,aAAA,CAAA,WAAA,CAAA,WAAA;kBACJ,aAAA,CAAA,WAAA,CAAA,OAAA;kBACA,aAAA,CAAA,WAAA,CAAA,OAAA;mBACC,aAAA,CAAA,WAAA,CAAA,QAAA;oBACC,aAAA,CAAA,WAAA,CAAA,SAAA;2BACO,aAAA,CAAA,WAAA,CAAA,SAAA;oDANV,QAAQ;sDAAR,QAAQ;AAOpB;;;;","names":[]}
1
+ {"version":3,"file":"skra-ui-layout.d.ts","sources":["../../../../libs/ui/layout/src/lib/box/box.ts","../../../../libs/ui/layout/src/lib/stack/stack.ts","../../../../libs/ui/layout/src/lib/grid/grid.ts","../../../../libs/ui/layout/src/lib/surface/surface.ts"],"mappings":";;AAOM,KAAM,UAAU;AAChB,KAAM,UAAU;AAEtB;;;;;;;;;;;AAWG;AACH,cAiBa,OAAO;sBACF,aAAA,CAAA,WAAA,CAAA,UAAA;sBACA,aAAA,CAAA,WAAA,CAAA,UAAA;oDAFL,OAAO;sDAAP,OAAO;AAGnB;;KClCW,cAAc;AACpB,KAAM,QAAQ;AACd,KAAM,UAAU;AAChB,KAAM,YAAY;AAExB;;;;;;;;;;;AAWG;AACH,cAoBa,SAAS;wBACF,aAAA,CAAA,WAAA,CAAA,cAAA;kBACN,aAAA,CAAA,WAAA,CAAA,QAAA;oBACE,aAAA,CAAA,WAAA,CAAA,UAAA;sBACE,aAAA,CAAA,WAAA,CAAA,YAAA;mBACH,aAAA,CAAA,wBAAA;oDALF,SAAS;sDAAT,SAAS;AAMrB;;KC5CW,WAAW;AASjB,KAAM,OAAO;AACb,KAAM,OAAO;AACb,KAAM,QAAQ;AACd,KAAM,SAAS;AAErB;;;;;;;;;;;;;;;;;AAiBG;AACH,cAqBa,QAAQ;sBACH,aAAA,CAAA,WAAA,CAAA,WAAA;kBACJ,aAAA,CAAA,WAAA,CAAA,OAAA;kBACA,aAAA,CAAA,WAAA,CAAA,OAAA;mBACC,aAAA,CAAA,WAAA,CAAA,QAAA;oBACC,aAAA,CAAA,WAAA,CAAA,SAAA;2BACO,aAAA,CAAA,WAAA,CAAA,SAAA;oDANV,QAAQ;sDAAR,QAAQ;AAOpB;;AC5DK,KAAM,cAAc;AAE1B;;;;;;;;;;;;;;;;;;AAkBG;AACH,cAca,WAAW;AACtB;;;;AAIG;sBACa,aAAA,CAAA,WAAA,CAAA,cAAA;oDANL,WAAW;sDAAX,WAAW;AAOvB;;;;","names":[]}