@skra/ui 0.7.0 → 0.9.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.
@@ -0,0 +1,360 @@
1
+ import * as i0 from '@angular/core';
2
+ import { SkraFieldContext } from '@skra/ui/field';
3
+
4
+ /** Leading icon of `<skra-file-upload>`'s face. Decorative — the consumer marks it `aria-hidden`. */
5
+ declare class SkraFileUploadStart {
6
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileUploadStart, never>;
7
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileUploadStart, "[skra-start]", never, {}, {}, never, never, true, never>;
8
+ }
9
+ /**
10
+ * REQUIRED. The visible action text of `<skra-file-upload>` ("Choose a video"). It joins the
11
+ * native control's accessible name through `aria-labelledby` (ADR 0056 D4, WCAG 2.5.3), so a
12
+ * voice-control user can say what they see.
13
+ */
14
+ declare class SkraFileUploadAction {
15
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileUploadAction, never>;
16
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileUploadAction, "[skra-file-upload-action]", never, {}, {}, never, never, true, never>;
17
+ }
18
+ /**
19
+ * The drop instruction ("or drag it here"). Its presence switches the face from the compact
20
+ * row to the drop-zone layout — an instruction is what invites dragging. Hidden on devices
21
+ * with no fine pointer, where "drag" means nothing.
22
+ */
23
+ declare class SkraFileUploadInstruction {
24
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileUploadInstruction, never>;
25
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileUploadInstruction, "[skra-file-upload-instruction]", never, {}, {}, never, never, true, never>;
26
+ }
27
+ /**
28
+ * The selection summary in the page's language ("recording.mp4, 2.3 GB"). Rendered inside the
29
+ * composite's always-present `role="status"` region and linked to the control as a description,
30
+ * so a change is announced and the user agent's browser-language status is not the only one.
31
+ */
32
+ declare class SkraFileUploadStatus {
33
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileUploadStatus, never>;
34
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileUploadStatus, "[skra-file-upload-status]", never, {}, {}, never, never, true, never>;
35
+ }
36
+ /** Leading visual of a file row — an icon or a consumer-made thumbnail (`URL.createObjectURL`). */
37
+ declare class SkraFileItemStart {
38
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileItemStart, never>;
39
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileItemStart, "[skra-start]", never, {}, {}, never, never, true, never>;
40
+ }
41
+ /** Row detail under the name — typically `progress[skraProgress]` or a status line. */
42
+ declare class SkraFileItemDetail {
43
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileItemDetail, never>;
44
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileItemDetail, "[skra-file-item-detail]", never, {}, {}, never, never, true, never>;
45
+ }
46
+ /**
47
+ * The row's error text. Its presence is what paints the row invalid
48
+ * (`data-skra-validation="invalid"`), so the colour never appears without the words
49
+ * (WCAG 1.4.1 by construction).
50
+ */
51
+ declare class SkraFileItemError {
52
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileItemError, never>;
53
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileItemError, "[skra-file-item-error]", never, {}, {}, never, never, true, never>;
54
+ }
55
+ /** Trailing row actions — the consumer's `button[skraButton]`s (cancel / retry / remove). */
56
+ declare class SkraFileItemEnd {
57
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileItemEnd, never>;
58
+ static ɵdir: i0.ɵɵDirectiveDeclaration<SkraFileItemEnd, "[skra-end]", never, {}, {}, never, never, true, never>;
59
+ }
60
+
61
+ /**
62
+ * Format a byte count for display in `locale` (`undefined` → the host default, the ADR 0050
63
+ * §5 precedent): `2,3 GB` in `pl`, `2.3 GB` in `en`, one fractional digit at most.
64
+ *
65
+ * SI units (1 kB = 1000 B) because `Intl` names only those and macOS / iOS report sizes the
66
+ * same way. The unit label is `Intl`'s own short form, so it is translated and pluralised by
67
+ * the platform's locale data, never by Skra (e.g. `999 byte` in English, `999 B` in Polish —
68
+ * CLDR's choice, not ours). A multi-GB `File.size` is a safe integer; nothing here rounds
69
+ * the input.
70
+ *
71
+ * @throws RangeError for a negative or non-finite count — a size that cannot exist is a bug
72
+ * in the caller, and printing `NaN byte` would hide it.
73
+ */
74
+ declare function skraFormatFileSize(bytes: number, locale?: string): string;
75
+ /**
76
+ * Does `file` satisfy `accept`, under the HTML attribute's own semantics?
77
+ *
78
+ * - `.ext` — a case-insensitive suffix of the file NAME;
79
+ * - `type/subtype` — the file's MIME type, case-insensitive, parameters ignored;
80
+ * - `type/*` — any subtype of `type`.
81
+ *
82
+ * An empty `accept`, or one with no token the grammar recognises, accepts everything — the
83
+ * picker applies no filter in that case either.
84
+ *
85
+ * **Typeless files** (`File.type === ''` — common for `.mkv` / `.heic` on some engines) are
86
+ * matched by extension tokens only, and PASS when `accept` has no extension token (spec Q-5).
87
+ * A false rejection of a legitimate 4 GB recording costs more than a junk file the consumer
88
+ * and the server reject anyway.
89
+ *
90
+ * `accept` is never a guarantee: every platform lets a user bypass it. Validate on the server.
91
+ */
92
+ declare function skraFileMatchesAccept(file: Pick<File, 'name' | 'type'>, accept: string): boolean;
93
+
94
+ /** Why the normalisation turned a file down. Every reason is a rule the PLATFORM's picker enforces. */
95
+ type SkraFileRejectionReason = 'type' | 'count' | 'directory';
96
+ /** A file the normalisation rejected, and why. */
97
+ interface SkraFileRejection {
98
+ readonly file: File;
99
+ readonly reason: SkraFileRejectionReason;
100
+ }
101
+
102
+ /**
103
+ * `input[type="file"][skraFileInput]` — the native file control (spec
104
+ * `component-file-upload-spec.md`; ADR 0056 Group B). A Component-on-a-native-host
105
+ * (ADR 040): `<input>` is void, so `template: ''`, and `file-input.scss` is scoped to the
106
+ * host by Emulated encapsulation — the box from `comp.field.*`, the user agent's
107
+ * `::file-selector-button` painted from `comp.field.file.*` (ADR 0056 B1–B5).
108
+ *
109
+ * **No inputs.** Every constraint is a NATIVE attribute on the consumer's own host —
110
+ * `accept`, `multiple`, `capture`, `required`, `disabled`, `name`, `webkitdirectory`
111
+ * (native-attr-first, Iron Boundary #9). Skra reads them at the moment of a selection; it
112
+ * never mirrors them.
113
+ *
114
+ * **Agnostic value (ADR 037).** The selection is REPORTED, never held: `filesChange` carries
115
+ * the normalised files, `filesRejected` what the normalisation turned down. Native
116
+ * `(change)` keeps working and reports the RAW selection; `filesChange` is the normalised one.
117
+ *
118
+ * **Normalisation** — Skra enforces exactly what the platform's own picker enforces, on
119
+ * every path, and nothing more (size / count caps / duplicates are product policy):
120
+ *
121
+ * | Rule | Picker (`change`) | Drop (`drop` on the host) |
122
+ * | --- | --- | --- |
123
+ * | `accept` mismatch → `type` | possible (Windows "All files", Android) | the browser applies no `accept` to drops |
124
+ * | >1 file without `multiple` → `count` | impossible | possible — ALL rejected |
125
+ * | a directory → `directory` | impossible | possible |
126
+ * | assignment | `input.files` left as the platform set it | `input.files` = the ACCEPTED files, then `input` + `change` are dispatched |
127
+ *
128
+ * A drop where nothing is accepted leaves the existing selection untouched and emits only
129
+ * `filesRejected` — like a cancelled picker, it is not a change.
130
+ *
131
+ * **Field wiring (ADR 013 §3.7)** — the `skraInput` wiring verbatim: optional
132
+ * `SkraFieldContext`; `id` / `disabled` written from guarded `effect()`s so a standalone
133
+ * consumer's own attributes survive; `aria-describedby` / `aria-invalid` / `aria-required`
134
+ * host bindings. Readonly: the native `readonly` attribute does not apply to `type="file"`
135
+ * (HTML) and `aria-readonly` is not exposed for its `button` role (G-4, measured), so it is
136
+ * `aria-disabled="true"` — the focusable soft-disable — plus a behaviour guard that blocks the
137
+ * picker (`click`, keys other than `Tab`) and drops.
138
+ *
139
+ * **Known limitation (G-4, measured in Chromium):** "required" cannot reach assistive
140
+ * technology on this control — neither `aria-required` (kept: harmless, and the field's
141
+ * contract) nor native `required` is exposed for the `button` role. Say "required" in visible
142
+ * text (the label or the hint) as well.
143
+ *
144
+ * **Inside `<skra-file-upload>`** (ADR 0056 Group D) the composite's context is injected:
145
+ * the host reflects `data-skra-in-upload` (ADR 027 §3.9b) and its own stylesheet makes it a
146
+ * transparent overlay over the painted face (`opacity: 0` only — D2); its name becomes
147
+ * "field label + visible action text" via `aria-labelledby` (D4, WCAG 2.5.3) and the
148
+ * composite's status region joins its description.
149
+ *
150
+ * <skra-field>
151
+ * <label skraLabelFor>Session recording</label>
152
+ * <input skraFileInput type="file" accept="video/*" #picker (filesChange)="onFiles($event)" />
153
+ * </skra-field>
154
+ */
155
+ declare class SkraFileInput {
156
+ private readonly el;
157
+ readonly context: SkraFieldContext | null;
158
+ private readonly upload;
159
+ /** User picked or dropped files. Fires on user interaction only, after normalisation. */
160
+ readonly filesChange: i0.OutputEmitterRef<readonly File[]>;
161
+ /** Files the normalisation rejected. Fires only when at least one was rejected. */
162
+ readonly filesRejected: i0.OutputEmitterRef<readonly SkraFileRejection[]>;
163
+ protected readonly inUpload: boolean;
164
+ protected readonly dragOver: i0.WritableSignal<boolean>;
165
+ private dragDepth;
166
+ protected readonly softDisabled: i0.Signal<boolean>;
167
+ protected readonly describedBy: i0.Signal<string | null>;
168
+ protected readonly labelledBy: i0.Signal<string | null>;
169
+ constructor();
170
+ /**
171
+ * Reset the native selection (`value = ''`) so the same file can be picked again — the
172
+ * queue model (`filesChange` → enqueue → `clear()`). Programmatic: emits nothing.
173
+ * Reach it through a template reference: `#picker` on the host resolves to this component.
174
+ */
175
+ clear(): void;
176
+ private get blocked();
177
+ /**
178
+ * The native constraints, read at selection time. A `webkitdirectory` picker hands over
179
+ * EVERY file of the chosen folder whether or not `multiple` is set, so it counts as
180
+ * multiple — otherwise each folder pick would be rejected whole as `count`.
181
+ */
182
+ private constraints;
183
+ /**
184
+ * The picker path — and the drop path's own dispatched `change`, already normalised.
185
+ *
186
+ * Order is part of the contract, the same on both paths: `filesChange` FIRST, then
187
+ * `filesRejected`. A consumer that clears its error on a new selection and sets it on a
188
+ * rejection then ends on the rejection message, not on a cleared one. A selection where
189
+ * EVERY file was rejected emits no `filesChange` at all (like a fully rejected drop): it
190
+ * changed nothing the consumer can use. An empty selection with no rejection (a picker
191
+ * that reports a cleared selection) still emits `filesChange([])`.
192
+ */
193
+ protected onChange(): void;
194
+ /** Readonly: `preventDefault` on `click` keeps the picker closed, for pointer and keyboard alike. */
195
+ protected blockWhenReadonly(event: Event): void;
196
+ /** Readonly: block keyboard activation; let `Tab` through. */
197
+ protected blockKeyWhenReadonly(event: KeyboardEvent): void;
198
+ protected onDragEnter(event: DragEvent): void;
199
+ protected onDragOver(event: DragEvent): void;
200
+ protected onDragLeave(): void;
201
+ protected resetDrag(): void;
202
+ /** The drop path — normalise, then assign the ACCEPTED files and replay the native events. */
203
+ protected onDrop(event: DragEvent): void;
204
+ /**
205
+ * Directory detection has to happen INSIDE the `drop` handler: `webkitGetAsEntry()` is the
206
+ * only cross-engine signal (a dropped folder arrives as a `File` too), and the item list
207
+ * is emptied once the event returns.
208
+ */
209
+ private candidatesOf;
210
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileInput, never>;
211
+ static ɵcmp: i0.ɵɵComponentDeclaration<SkraFileInput, "input[type=\"file\"][skraFileInput]", never, {}, { "filesChange": "filesChange"; "filesRejected": "filesRejected"; }, never, never, true, never>;
212
+ }
213
+
214
+ /**
215
+ * Internal — provided by `<skra-file-upload>` per instance, injected `{ optional: true }` by
216
+ * the projected `input[skraFileInput]` (ADR 013 §3.6 contextual wiring). Carries ids only —
217
+ * never a value, never state (ADR 037; the composite owns no state, ADR 027 §3.8).
218
+ *
219
+ * Its PRESENCE is what puts the input into overlay mode (`data-skra-in-upload`, ADR 027
220
+ * §3.9b): Emulated encapsulation lets no parent style projected content, and DI keeps the
221
+ * rule in the atom's own stylesheet instead of a global slice (no O-8 bridge cost).
222
+ */
223
+ declare class SkraFileUploadContext {
224
+ private readonly base;
225
+ /** The face's visible action text — the second half of the control's name (ADR 0056 D4). */
226
+ readonly actionId: string;
227
+ /** The always-present status region — a description of the control, never its name. */
228
+ readonly statusId: string;
229
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileUploadContext, never>;
230
+ static ɵprov: i0.ɵɵInjectableDeclaration<SkraFileUploadContext>;
231
+ }
232
+
233
+ /**
234
+ * `<skra-file-upload>` — the optional enhancement over a projected `input[skraFileInput]`
235
+ * (spec `component-file-upload-spec.md`; ADR 0056 Group D). It paints a localisable face —
236
+ * the action and the instruction in the PAGE's language, from tokens — enlarges the control
237
+ * into a drop zone, and hosts the live selection-status region.
238
+ *
239
+ * Why it exists: the native control's two strings ("Choose File" / "No file chosen") come
240
+ * from the browser's UI language, not the page's `lang`, and no CSS or attribute can replace
241
+ * them (ADR 0056 §1.6). The native control stays THE control (D2): transparent
242
+ * (`opacity: 0`, its own stylesheet, switched on by this component's context), covering the
243
+ * whole face, it remains the focus target, the pointer target, the drop target and the node
244
+ * assistive technology reads — so `required`, `aria-invalid`, the validation bubble, label
245
+ * activation, form submission and the iOS camera / library sheet all keep working.
246
+ *
247
+ * **State-READING** (ADR 027 §3.8, ADR 055): no inputs, no outputs; every state it paints —
248
+ * hover, focus-visible, drag-over, disabled, readonly, invalid — is read from the projected
249
+ * control through `:has()`. It owns no state, so it mirrors no ARIA.
250
+ *
251
+ * **Layout follows content (ADR 020).** No `[skra-file-upload-instruction]` → a compact,
252
+ * field-like row (`[icon] [action] status`); with one → the drop-zone layout (stacked,
253
+ * centred, dashed). Both accept drops. There is no look input (skin philosophy).
254
+ *
255
+ * **Never project interactive content** into it — the transparent control covers the whole
256
+ * face and swallows the clicks (D3). The file list is a SIBLING.
257
+ *
258
+ * **Page-navigation guard.** While one is mounted, a FILE drag dropped outside every drop
259
+ * target is cancelled instead of navigating the page to the file (spec Q-3; text / link
260
+ * drags, native file inputs and editable content are untouched).
261
+ *
262
+ * <skra-field [hasError]="!!error()">
263
+ * <label skraLabelFor>Session recording</label>
264
+ * <skra-file-upload>
265
+ * <span skra-file-upload-action>Choose a video</span>
266
+ * <span skra-file-upload-instruction>or drag it here</span>
267
+ * <span skra-file-upload-status>{{ summary() }}</span>
268
+ * <input skraFileInput type="file" accept="video/*" (filesChange)="onFiles($event)" />
269
+ * </skra-file-upload>
270
+ * <skra-error>{{ error() }}</skra-error>
271
+ * </skra-field>
272
+ */
273
+ declare class SkraFileUpload {
274
+ protected readonly ctx: SkraFileUploadContext;
275
+ private readonly host;
276
+ private readonly start;
277
+ private readonly action;
278
+ private readonly instruction;
279
+ private readonly status;
280
+ private readonly inputs;
281
+ private readonly nestedInputs;
282
+ protected readonly hasStart: i0.Signal<boolean>;
283
+ protected readonly hasInstruction: i0.Signal<boolean>;
284
+ protected readonly hasStatus: i0.Signal<boolean>;
285
+ constructor();
286
+ /**
287
+ * Dev-only, ADR 0056 D3: the face is paint. Anything interactive projected into it sits
288
+ * UNDER the transparent control, so the control swallows its clicks — and inside the
289
+ * `aria-hidden` face it is hidden from assistive technology while still focusable. A read of
290
+ * the rendered face, never a write.
291
+ */
292
+ private warnInteractiveFace;
293
+ /** Dev-only: the composite cannot work without exactly one direct-child control and an action. */
294
+ private warnMisuse;
295
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileUpload, never>;
296
+ static ɵcmp: i0.ɵɵComponentDeclaration<SkraFileUpload, "skra-file-upload", never, {}, {}, ["start", "action", "instruction", "status", "inputs", "nestedInputs"], ["[skra-start]", "[skra-file-upload-action]", "[skra-file-upload-instruction]", "[skra-file-upload-status]", "input[skraFileInput]"], true, never>;
297
+ }
298
+
299
+ /** A file name split for middle truncation: the stem may shrink, the extension never does. */
300
+ interface SkraFileNameParts {
301
+ readonly stem: string;
302
+ readonly ext: string;
303
+ }
304
+
305
+ /**
306
+ * `li[skraFileItem]` — a display row for ONE consumer-owned file (spec
307
+ * `component-file-upload-spec.md`). A Component-on-a-native-host (ADR 012 / ADR 040): the
308
+ * `<li>` keeps its list-item semantics inside the consumer's `ul[skraStack]`.
309
+ *
310
+ * Separate from `<skra-file-upload>` by SRP: a row outlives the selection (it tracks an
311
+ * upload), its source of truth is the consumer's queue — not `input.files` — and it is a
312
+ * display list item, not a form control. **Skra never uploads**: progress, retry, cancel and
313
+ * removal are the consumer's, projected into the row's slots.
314
+ *
315
+ * - **Name**, middle-truncated with the extension always visible — pure CSS, no measurement.
316
+ * The visual split is `aria-hidden`; an `[skra-sr-only]` copy carries the whole name.
317
+ * - **Size** — `skraFormatFileSize(size, locale)`: SI units, `Intl` short labels, the
318
+ * `locale` input or the host default (the ADR 0050 §5 precedent).
319
+ * - **Invalid is READ, never owned** (ADR 027 §3.8, spec Q-7): the row paints
320
+ * `data-skra-validation="invalid"` only while `[skra-file-item-error]` text is projected, so
321
+ * the colour never appears without the words (WCAG 1.4.1 by construction). No `aria-invalid`
322
+ * — no role an `<li>` holds supports it.
323
+ *
324
+ * <ul skraStack>
325
+ * @for (u of uploads(); track u.id) {
326
+ * <li skraFileItem [name]="u.file.name" [size]="u.file.size" locale="pl-PL">
327
+ * <progress skraProgress skra-file-item-detail [value]="u.sent" [max]="u.file.size"
328
+ * [attr.aria-label]="'Uploading ' + u.file.name"></progress>
329
+ * @if (u.error) { <span skra-file-item-error>{{ u.error }}</span> }
330
+ * <button skraButton skra-end emphasis="low" (click)="cancel(u)">
331
+ * Cancel<span skra-sr-only> {{ u.file.name }}</span>
332
+ * </button>
333
+ * </li>
334
+ * }
335
+ * </ul>
336
+ */
337
+ declare class SkraFileItem {
338
+ /** The file name, shown as stem + extension. */
339
+ readonly name: i0.InputSignal<string>;
340
+ /** Size in bytes, formatted for display. `undefined` → no size shown. */
341
+ readonly size: i0.InputSignal<number | undefined>;
342
+ /** `Intl` locale for the size. `undefined` → the host default (ADR 0050 §5 precedent). */
343
+ readonly locale: i0.InputSignal<string | undefined>;
344
+ private readonly start;
345
+ private readonly detail;
346
+ private readonly error;
347
+ private readonly end;
348
+ protected readonly hasStart: i0.Signal<boolean>;
349
+ protected readonly hasDetail: i0.Signal<boolean>;
350
+ protected readonly hasError: i0.Signal<boolean>;
351
+ protected readonly hasEnd: i0.Signal<boolean>;
352
+ protected readonly parts: i0.Signal<SkraFileNameParts>;
353
+ protected readonly sizeLabel: i0.Signal<string>;
354
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraFileItem, never>;
355
+ static ɵcmp: i0.ɵɵComponentDeclaration<SkraFileItem, "li[skraFileItem]", never, { "name": { "alias": "name"; "required": true; "isSignal": true; }; "size": { "alias": "size"; "required": false; "isSignal": true; }; "locale": { "alias": "locale"; "required": false; "isSignal": true; }; }, {}, ["start", "detail", "error", "end"], ["[skra-start]", "[skra-file-item-detail]", "[skra-file-item-error]", "[skra-end]"], true, never>;
356
+ }
357
+
358
+ export { SkraFileInput, SkraFileItem, SkraFileItemDetail, SkraFileItemEnd, SkraFileItemError, SkraFileItemStart, SkraFileUpload, SkraFileUploadAction, SkraFileUploadInstruction, SkraFileUploadStart, SkraFileUploadStatus, skraFileMatchesAccept, skraFormatFileSize };
359
+ export type { SkraFileRejection, SkraFileRejectionReason };
360
+ //# sourceMappingURL=skra-ui-file-upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skra-ui-file-upload.d.ts","sources":["../../../../libs/ui/file-upload/src/lib/file-upload.directives.ts","../../../../libs/ui/file-upload/src/lib/file-helpers/file-helpers.ts","../../../../libs/ui/file-upload/src/lib/file-helpers/file-partition.ts","../../../../libs/ui/file-upload/src/lib/file-input/file-input.ts","../../../../libs/ui/file-upload/src/lib/file-upload/file-upload-context.ts","../../../../libs/ui/file-upload/src/lib/file-upload/file-upload.ts","../../../../libs/ui/file-upload/src/lib/file-helpers/file-name.ts","../../../../libs/ui/file-upload/src/lib/file-item/file-item.ts"],"mappings":";;;AAUA;AACA,cAIa,mBAAmB;yCAAnB,mBAAmB;2CAAnB,mBAAmB;AAAG;AAEnC;;;;AAIG;AACH,cAIa,oBAAoB;yCAApB,oBAAoB;2CAApB,oBAAoB;AAAG;AAEpC;;;;AAIG;AACH,cAIa,yBAAyB;yCAAzB,yBAAyB;2CAAzB,yBAAyB;AAAG;AAEzC;;;;AAIG;AACH,cAIa,oBAAoB;yCAApB,oBAAoB;2CAApB,oBAAoB;AAAG;AAIpC;AACA,cAIa,iBAAiB;yCAAjB,iBAAiB;2CAAjB,iBAAiB;AAAG;AAEjC;AACA,cAIa,kBAAkB;yCAAlB,kBAAkB;2CAAlB,kBAAkB;AAAG;AAElC;;;;AAIG;AACH,cAIa,iBAAiB;yCAAjB,iBAAiB;2CAAjB,iBAAiB;AAAG;AAEjC;AACA,cAIa,eAAe;yCAAf,eAAe;2CAAf,eAAe;AAAG;;AClE/B;;;;;;;;;;;;AAYG;AACH,iBAAgB,kBAAkB;AAoDlC;;;;;;;;;;;;;;;;AAgBG;AACH,iBAAgB,qBAAqB,OAC7B,IAAI,CAAC,IAAI;;ACjGjB;AACM,KAAM,uBAAuB;AAEnC;UACiB,iBAAiB;AAChC,mBAAe,IAAI;AACnB,qBAAiB,uBAAuB;AACzC;;ACwBD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDG;AACH,cAmCa,aAAa;AACxB;sBACgB,gBAAA;AAChB;;0BAGoBA,EAAA,CAAA,gBAAA,UAAA,IAAA;;4BAGEA,EAAA,CAAA,gBAAA,UAAA,iBAAA;AAEtB;AACA,iCAA2BA,EAAA,CAAA,cAAA;;AAQ3B,qCAA+BA,EAAA,CAAA,MAAA;AAI/B,oCAA8BA,EAAA,CAAA,MAAA;AAS9B,mCAA6BA,EAAA,CAAA,MAAA;;AA0C7B;;;;AAIG;AACH;;AAQA;;;;AAIG;AACH;AAKA;;;;;;;;;AASG;;;AAYH,uCAAmC,KAAK;;AAKxC,0CAAsC,aAAa;AAMnD,iCAA6B,SAAS;AAOtC,gCAA4B,SAAS;;;;AA6BrC,4BAAwB,SAAS;AA0BjC;;;;AAIG;AACH;yCArMW,aAAa;2CAAb,aAAa;AA2NzB;;ACjVD;;;;;;;;AAQG;AACH,cACa,qBAAqB;AAChC;;;;;yCADW,qBAAqB;6CAArB,qBAAqB;AAQjC;;ACID;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCG;AACH,cAea,cAAc;AACzB,4BAAsB,qBAAA;AACtB;AAIA;AAGA;AAGA;AAGA;AAIA;AACA;AAIA,iCAA2BA,EAAA,CAAA,MAAA;AAC3B,uCAAiCA,EAAA,CAAA,MAAA;AACjC,kCAA4BA,EAAA,CAAA,MAAA;;AAmB5B;;;;;AAKG;AACH;;AAkBA;yCArEW,cAAc;2CAAd,cAAc;AAiG1B;;ACjLD;UACiB,iBAAiB;AAChC;AACA;AACD;;ACaD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BG;AACH,cAiBa,YAAY;;mBAEVA,EAAA,CAAA,WAAA;;mBAGAA,EAAA,CAAA,WAAA;;qBAGEA,EAAA,CAAA,WAAA;AAKf;AAGA;AAGA;AAGA;AAEA,iCAA2BA,EAAA,CAAA,MAAA;AAC3B,kCAA4BA,EAAA,CAAA,MAAA;AAC5B,iCAA2BA,EAAA,CAAA,MAAA;AAC3B,+BAAyBA,EAAA,CAAA,MAAA;AAEzB,8BAAwBA,EAAA,CAAA,MAAA,CAAAC,iBAAA;AAIxB,kCAA4BD,EAAA,CAAA,MAAA;yCAjCjB,YAAY;2CAAZ,YAAY;AAsCxB;;;;","names":["_angular_core","___file_helpers_file_name.SkraFileNameParts"]}
@@ -23,7 +23,7 @@ declare class SkraBox {
23
23
 
24
24
  type StackDirection = 'row' | 'column';
25
25
  type StackGap = 'none' | 'sm' | 'md' | 'lg';
26
- type StackAlign = 'start' | 'center' | 'end' | 'stretch';
26
+ type StackAlign = 'start' | 'center' | 'end' | 'stretch' | 'baseline';
27
27
  type StackJustify = 'start' | 'center' | 'end' | 'between' | 'around';
28
28
  /**
29
29
  * SkraStack — flex layout primitive that arranges its children (ADR 041).
@@ -112,6 +112,35 @@ declare class SkraSurface {
112
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
113
  }
114
114
 
115
- export { SkraBox, SkraGrid, SkraStack, SkraSurface };
115
+ /**
116
+ * SkraSurfaceLink — the stretched-link marker that makes a whole `SkraSurface`
117
+ * one activation target (ADR 0055 R3/R4).
118
+ *
119
+ * Placed on the consumer's OWN primary control — `<a>` for navigation, `<button>`
120
+ * where the destination is an action — never on the Surface host (R3.1:
121
+ * `a[skraSurface]` / `button[skraSurface]` stay unsupported). Its own host
122
+ * stylesheet stretches the control's hit area over the nearest Surface with a
123
+ * `::after` overlay; the Surface reads `:has([skraSurfaceLink]…)` and paints hover
124
+ * and the focus ring on itself, because the surface is the target (R4.2).
125
+ *
126
+ * Accessible name: the control's own visible text (ADR 033 Path 1) — normally the
127
+ * card's heading. No inputs, no `aria-*`, no `role`, no `tabindex`: the native
128
+ * host already is the one tab stop.
129
+ *
130
+ * Dev-mode console errors (R3.3): no `[skraSurface]` ancestor (the overlay would
131
+ * stretch over whatever positioned ancestor happens to exist — possibly the whole
132
+ * page), and more than one marker whose NEAREST Surface is the same (two overlays
133
+ * = an invisible hit-area conflict). Checked on the rendered DOM, not through DI:
134
+ * a consumer's own card component projecting content into `<article skraSurface>`
135
+ * puts the marker inside the Surface in the DOM while its injector chain follows
136
+ * the declaring template and never meets the Surface.
137
+ */
138
+ declare class SkraSurfaceLink {
139
+ constructor();
140
+ static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkraSurfaceLink, never>;
141
+ static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraSurfaceLink, "a[skraSurfaceLink], button[skraSurfaceLink]", never, {}, {}, never, ["*"], true, never>;
142
+ }
143
+
144
+ export { SkraBox, SkraGrid, SkraStack, SkraSurface, SkraSurfaceLink };
116
145
  export type { BoxDisplay, BoxPadding, GridAlign, GridColumns, GridFlow, GridGap, GridMin, StackAlign, StackDirection, StackGap, StackJustify, SurfacePadding };
117
146
  //# 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","../../../../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":[]}
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","../../../../libs/ui/layout/src/lib/surface/surface-link.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;;ACtCD;;;;;;;;;;;;;;;;;;;;;;AAsBG;AACH,cAQa,eAAe;;oDAAf,eAAe;sDAAf,eAAe;AAS3B;;;;","names":[]}
@@ -16,5 +16,32 @@ declare class SkraLink {
16
16
  static ɵcmp: i0.ɵɵComponentDeclaration<SkraLink, "a[skraLink]", never, {}, {}, never, ["*"], true, never>;
17
17
  }
18
18
 
19
- export { SkraLink };
19
+ /**
20
+ * SkraNavLink — a navigation destination with a visible current state (ADR 0060).
21
+ *
22
+ * Selector: `a[skraNavLink]` — `<a>` is the sole host (R1: a nav item that does not
23
+ * navigate is not a nav item). A separate atom from `skraLink`: the surface shape and
24
+ * the current state belong to navigation chrome, `:visited` and the underline to prose.
25
+ *
26
+ * **A navigation link is a link.** It keeps every native `<a>` behaviour and owns no
27
+ * state: zero inputs, zero outputs, no host attributes. The current state is READ from
28
+ * the native `aria-current` the consumer or the router already sets
29
+ * (`routerLinkActive` + `ariaCurrentWhenActive="page"`) — the component never writes it,
30
+ * so the paint and what assistive technology announces cannot disagree (R3).
31
+ *
32
+ * No `intent`/`emphasis`/`size` (R2 — the guardrail that keeps the marketing CTA out,
33
+ * ADR 032 §3.5), no `disabled` (ADR 032 §3.6.3), no `ariaLabel` (ADR 033 Path 1: the
34
+ * visible text is the name).
35
+ *
36
+ * Dev-mode console error (R5.1): a nav link outside a navigation landmark (`<nav>` or
37
+ * `role="navigation"`). Checked on the rendered DOM, not through DI — a consumer
38
+ * component that projects the link into its own `<nav>` must not trip it.
39
+ */
40
+ declare class SkraNavLink {
41
+ constructor();
42
+ static ɵfac: i0.ɵɵFactoryDeclaration<SkraNavLink, never>;
43
+ static ɵcmp: i0.ɵɵComponentDeclaration<SkraNavLink, "a[skraNavLink]", never, {}, {}, never, ["*"], true, never>;
44
+ }
45
+
46
+ export { SkraLink, SkraNavLink };
20
47
  //# sourceMappingURL=skra-ui-link.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skra-ui-link.d.ts","sources":["../../../../libs/ui/link/src/lib/link/link.ts"],"mappings":";;AAMA;;;;;;;;;;AAUG;AACH,cAQa,QAAQ;yCAAR,QAAQ;2CAAR,QAAQ;AAAG;;;;","names":[]}
1
+ {"version":3,"file":"skra-ui-link.d.ts","sources":["../../../../libs/ui/link/src/lib/link/link.ts","../../../../libs/ui/link/src/lib/nav-link/nav-link.ts"],"mappings":";;AAMA;;;;;;;;;;AAUG;AACH,cAQa,QAAQ;yCAAR,QAAQ;2CAAR,QAAQ;AAAG;;ACdxB;;;;;;;;;;;;;;;;;;;;AAoBG;AACH,cAQa,WAAW;;yCAAX,WAAW;2CAAX,WAAW;AAiBvB;;;;","names":[]}