@skra/ui 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/consumer-guide/README.md +92 -88
- package/consumer-guide/accessible-names.md +2 -1
- package/consumer-guide/feedback.md +100 -0
- package/consumer-guide/file-upload.md +210 -0
- package/consumer-guide/setup-and-gotchas.md +37 -36
- package/fesm2022/skra-ui-alert.mjs +55 -6
- package/fesm2022/skra-ui-alert.mjs.map +1 -1
- package/fesm2022/skra-ui-button.mjs +2 -2
- package/fesm2022/skra-ui-button.mjs.map +1 -1
- package/fesm2022/skra-ui-chip.mjs +2 -2
- package/fesm2022/skra-ui-chip.mjs.map +1 -1
- package/fesm2022/skra-ui-core.mjs +2 -2
- package/fesm2022/skra-ui-core.mjs.map +1 -1
- package/fesm2022/skra-ui-file-upload.mjs +894 -0
- package/fesm2022/skra-ui-file-upload.mjs.map +1 -0
- package/fesm2022/skra-ui-toast.mjs +2 -2
- package/fesm2022/skra-ui-toast.mjs.map +1 -1
- package/package.json +6 -2
- package/types/skra-ui-alert.d.ts +39 -2
- package/types/skra-ui-alert.d.ts.map +1 -1
- package/types/skra-ui-file-upload.d.ts +360 -0
- package/types/skra-ui-file-upload.d.ts.map +1 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skra-ui-file-upload.mjs","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-upload/file-upload-context.ts","../../../../libs/ui/file-upload/src/lib/file-input/file-input.ts","../../../../libs/ui/file-upload/src/lib/file-upload/file-drop-guard.ts","../../../../libs/ui/file-upload/src/lib/file-upload/file-upload.ts","../../../../libs/ui/file-upload/src/lib/file-upload/file-upload.html","../../../../libs/ui/file-upload/src/lib/file-helpers/file-name.ts","../../../../libs/ui/file-upload/src/lib/file-item/file-item.ts","../../../../libs/ui/file-upload/src/lib/file-item/file-item.html","../../../../libs/ui/file-upload/src/index.ts","../../../../libs/ui/file-upload/src/skra-ui-file-upload.ts"],"sourcesContent":["import { Directive } from '@angular/core';\r\n\r\n// Slot markers of the FileUpload family (ADR 020 Smart Slots v2.0). Each is detected\r\n// through a Signal Query so the owning component renders a slot's wrapper only when the\r\n// slot is filled — never an empty node. Entry-local (the Button / Accordion precedent)\r\n// to avoid a cross-entry marker dependency. Import the markers you use alongside the\r\n// component: projection works on the attribute alone, but slot DETECTION needs the class.\r\n\r\n// ─── <skra-file-upload> ──────────────────────────────────────────────────────\r\n\r\n/** Leading icon of `<skra-file-upload>`'s face. Decorative — the consumer marks it `aria-hidden`. */\r\n@Directive({\r\n selector: '[skra-start]',\r\n standalone: true,\r\n})\r\nexport class SkraFileUploadStart {}\r\n\r\n/**\r\n * REQUIRED. The visible action text of `<skra-file-upload>` (\"Choose a video\"). It joins the\r\n * native control's accessible name through `aria-labelledby` (ADR 0056 D4, WCAG 2.5.3), so a\r\n * voice-control user can say what they see.\r\n */\r\n@Directive({\r\n selector: '[skra-file-upload-action]',\r\n standalone: true,\r\n})\r\nexport class SkraFileUploadAction {}\r\n\r\n/**\r\n * The drop instruction (\"or drag it here\"). Its presence switches the face from the compact\r\n * row to the drop-zone layout — an instruction is what invites dragging. Hidden on devices\r\n * with no fine pointer, where \"drag\" means nothing.\r\n */\r\n@Directive({\r\n selector: '[skra-file-upload-instruction]',\r\n standalone: true,\r\n})\r\nexport class SkraFileUploadInstruction {}\r\n\r\n/**\r\n * The selection summary in the page's language (\"recording.mp4, 2.3 GB\"). Rendered inside the\r\n * composite's always-present `role=\"status\"` region and linked to the control as a description,\r\n * so a change is announced and the user agent's browser-language status is not the only one.\r\n */\r\n@Directive({\r\n selector: '[skra-file-upload-status]',\r\n standalone: true,\r\n})\r\nexport class SkraFileUploadStatus {}\r\n\r\n// ─── li[skraFileItem] ────────────────────────────────────────────────────────\r\n\r\n/** Leading visual of a file row — an icon or a consumer-made thumbnail (`URL.createObjectURL`). */\r\n@Directive({\r\n selector: '[skra-start]',\r\n standalone: true,\r\n})\r\nexport class SkraFileItemStart {}\r\n\r\n/** Row detail under the name — typically `progress[skraProgress]` or a status line. */\r\n@Directive({\r\n selector: '[skra-file-item-detail]',\r\n standalone: true,\r\n})\r\nexport class SkraFileItemDetail {}\r\n\r\n/**\r\n * The row's error text. Its presence is what paints the row invalid\r\n * (`data-skra-validation=\"invalid\"`), so the colour never appears without the words\r\n * (WCAG 1.4.1 by construction).\r\n */\r\n@Directive({\r\n selector: '[skra-file-item-error]',\r\n standalone: true,\r\n})\r\nexport class SkraFileItemError {}\r\n\r\n/** Trailing row actions — the consumer's `button[skraButton]`s (cancel / retry / remove). */\r\n@Directive({\r\n selector: '[skra-end]',\r\n standalone: true,\r\n})\r\nexport class SkraFileItemEnd {}\r\n","// The two \"How\" helpers of the FileUpload family — pure, framework-free and SSR-safe (no\r\n// DOM access; `File` is used as a type and read through `name` / `type` only). Every\r\n// consumer otherwise reimplements them, and each has a subtle edge that is easy to get\r\n// wrong: 1000 vs 1024, a rounded value that crosses a unit boundary, the HTML `accept`\r\n// grammar, and files the platform reports with no MIME type at all.\r\n\r\n/** SI units, 1 kB = 1000 B — the `Intl` unit identifiers, and what macOS / iOS show. */\r\nconst UNITS = [\r\n 'byte',\r\n 'kilobyte',\r\n 'megabyte',\r\n 'gigabyte',\r\n 'terabyte',\r\n 'petabyte',\r\n] as const;\r\n\r\n/**\r\n * Format a byte count for display in `locale` (`undefined` → the host default, the ADR 0050\r\n * §5 precedent): `2,3 GB` in `pl`, `2.3 GB` in `en`, one fractional digit at most.\r\n *\r\n * SI units (1 kB = 1000 B) because `Intl` names only those and macOS / iOS report sizes the\r\n * same way. The unit label is `Intl`'s own short form, so it is translated and pluralised by\r\n * the platform's locale data, never by Skra (e.g. `999 byte` in English, `999 B` in Polish —\r\n * CLDR's choice, not ours). A multi-GB `File.size` is a safe integer; nothing here rounds\r\n * the input.\r\n *\r\n * @throws RangeError for a negative or non-finite count — a size that cannot exist is a bug\r\n * in the caller, and printing `NaN byte` would hide it.\r\n */\r\nexport function skraFormatFileSize(bytes: number, locale?: string): string {\r\n if (!Number.isFinite(bytes) || bytes < 0) {\r\n throw new RangeError(\r\n `skraFormatFileSize: expected a finite, non-negative byte count, got ${bytes}.`,\r\n );\r\n }\r\n let index = 0;\r\n while (index < UNITS.length - 1 && bytes >= 1000 ** (index + 1)) index += 1;\r\n // A value that ROUNDS up to 1000 of its unit reads as the next unit: 999 950 B is\r\n // \"1 MB\", not \"1,000 kB\".\r\n if (\r\n index < UNITS.length - 1 &&\r\n Math.round((bytes / 1000 ** index) * 10) / 10 >= 1000\r\n ) {\r\n index += 1;\r\n }\r\n return new Intl.NumberFormat(locale, {\r\n style: 'unit',\r\n unit: UNITS[index],\r\n unitDisplay: 'short',\r\n maximumFractionDigits: 1,\r\n }).format(bytes / 1000 ** index);\r\n}\r\n\r\n/** One parsed `accept` token. Tokens the HTML grammar does not recognise are dropped. */\r\ntype AcceptToken =\r\n | { kind: 'extension'; value: string }\r\n | { kind: 'mime'; value: string }\r\n | { kind: 'wildcard'; value: string };\r\n\r\nfunction parseAccept(accept: string): AcceptToken[] {\r\n const tokens: AcceptToken[] = [];\r\n for (const raw of accept.split(',')) {\r\n const token = raw.trim().toLowerCase();\r\n if (token.length > 1 && token.startsWith('.')) {\r\n tokens.push({ kind: 'extension', value: token });\r\n continue;\r\n }\r\n // `type/subtype` or `type/*`; parameters (`;charset=…`) never take part in a match.\r\n const mime = token.split(';')[0].trim();\r\n const slash = mime.indexOf('/');\r\n if (slash <= 0 || slash === mime.length - 1) continue;\r\n const subtype = mime.slice(slash + 1);\r\n if (subtype === '*') {\r\n tokens.push({ kind: 'wildcard', value: mime.slice(0, slash + 1) });\r\n } else {\r\n tokens.push({ kind: 'mime', value: mime });\r\n }\r\n }\r\n return tokens;\r\n}\r\n\r\n/**\r\n * Does `file` satisfy `accept`, under the HTML attribute's own semantics?\r\n *\r\n * - `.ext` — a case-insensitive suffix of the file NAME;\r\n * - `type/subtype` — the file's MIME type, case-insensitive, parameters ignored;\r\n * - `type/*` — any subtype of `type`.\r\n *\r\n * An empty `accept`, or one with no token the grammar recognises, accepts everything — the\r\n * picker applies no filter in that case either.\r\n *\r\n * **Typeless files** (`File.type === ''` — common for `.mkv` / `.heic` on some engines) are\r\n * matched by extension tokens only, and PASS when `accept` has no extension token (spec Q-5).\r\n * A false rejection of a legitimate 4 GB recording costs more than a junk file the consumer\r\n * and the server reject anyway.\r\n *\r\n * `accept` is never a guarantee: every platform lets a user bypass it. Validate on the server.\r\n */\r\nexport function skraFileMatchesAccept(\r\n file: Pick<File, 'name' | 'type'>,\r\n accept: string,\r\n): boolean {\r\n const tokens = parseAccept(accept);\r\n if (!tokens.length) return true;\r\n\r\n const name = file.name.toLowerCase();\r\n const type = file.type.trim().toLowerCase().split(';')[0].trim();\r\n const extensions = tokens.filter((t) => t.kind === 'extension');\r\n\r\n if (extensions.some((t) => name.endsWith(t.value))) return true;\r\n if (!type) return extensions.length === 0;\r\n\r\n return tokens.some(\r\n (t) =>\r\n (t.kind === 'mime' && t.value === type) ||\r\n (t.kind === 'wildcard' && type.startsWith(t.value)),\r\n );\r\n}\r\n","import { skraFileMatchesAccept } from './file-helpers';\r\n\r\n/** Why the normalisation turned a file down. Every reason is a rule the PLATFORM's picker enforces. */\r\nexport type SkraFileRejectionReason = 'type' | 'count' | 'directory';\r\n\r\n/** A file the normalisation rejected, and why. */\r\nexport interface SkraFileRejection {\r\n readonly file: File;\r\n readonly reason: SkraFileRejectionReason;\r\n}\r\n\r\n/** One selected item. `isDirectory` can only be true on the drop path. */\r\nexport interface SkraFileCandidate {\r\n readonly file: File;\r\n readonly isDirectory: boolean;\r\n}\r\n\r\n/** The native constraints Skra reads from the host — never mirrored as inputs. */\r\nexport interface SkraFileConstraints {\r\n readonly accept: string;\r\n readonly multiple: boolean;\r\n}\r\n\r\nexport interface SkraFilePartition {\r\n readonly accepted: File[];\r\n readonly rejected: SkraFileRejection[];\r\n}\r\n\r\n/**\r\n * Internal — NOT part of the public barrel. Partition one selection into accepted and\r\n * rejected files, enforcing exactly what the platform's own picker enforces and nothing more\r\n * (size, file count caps and duplicates are product policy — the consumer's, in `filesChange`).\r\n *\r\n * Precedence, one reason per file:\r\n * 1. `directory` — a dropped folder is never a file;\r\n * 2. `count` — more than one file on a control without `multiple` rejects ALL of them: a\r\n * single-file control never silently keeps one of N (spec Q-6);\r\n * 3. `type` — the file does not satisfy `accept` (`skraFileMatchesAccept`, typeless → Q-5).\r\n *\r\n * Order is preserved within both lists.\r\n */\r\nexport function partitionFiles(\r\n candidates: readonly SkraFileCandidate[],\r\n constraints: SkraFileConstraints,\r\n): SkraFilePartition {\r\n const accepted: File[] = [];\r\n const rejected: SkraFileRejection[] = [];\r\n const tooMany =\r\n !constraints.multiple &&\r\n candidates.filter((c) => !c.isDirectory).length > 1;\r\n\r\n for (const { file, isDirectory } of candidates) {\r\n if (isDirectory) rejected.push({ file, reason: 'directory' });\r\n else if (tooMany) rejected.push({ file, reason: 'count' });\r\n else if (skraFileMatchesAccept(file, constraints.accept))\r\n accepted.push(file);\r\n else rejected.push({ file, reason: 'type' });\r\n }\r\n return { accepted, rejected };\r\n}\r\n","import { Injectable, inject } from '@angular/core';\r\nimport { IdGeneratorService } from '@skra/ui/field';\r\n\r\n/**\r\n * Internal — provided by `<skra-file-upload>` per instance, injected `{ optional: true }` by\r\n * the projected `input[skraFileInput]` (ADR 013 §3.6 contextual wiring). Carries ids only —\r\n * never a value, never state (ADR 037; the composite owns no state, ADR 027 §3.8).\r\n *\r\n * Its PRESENCE is what puts the input into overlay mode (`data-skra-in-upload`, ADR 027\r\n * §3.9b): Emulated encapsulation lets no parent style projected content, and DI keeps the\r\n * rule in the atom's own stylesheet instead of a global slice (no O-8 bridge cost).\r\n */\r\n@Injectable()\r\nexport class SkraFileUploadContext {\r\n private readonly base = inject(IdGeneratorService).nextId('skra-file-upload');\r\n\r\n /** The face's visible action text — the second half of the control's name (ADR 0056 D4). */\r\n readonly actionId = `${this.base}-action`;\r\n\r\n /** The always-present status region — a description of the control, never its name. */\r\n readonly statusId = `${this.base}-status`;\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ElementRef,\r\n ViewEncapsulation,\r\n afterNextRender,\r\n computed,\r\n effect,\r\n inject,\r\n output,\r\n signal,\r\n} from '@angular/core';\r\nimport { SkraFieldContext } from '@skra/ui/field';\r\nimport {\r\n partitionFiles,\r\n type SkraFileCandidate,\r\n type SkraFileRejection,\r\n} from '../file-helpers/file-partition';\r\nimport { SkraFileUploadContext } from '../file-upload/file-upload-context';\r\n\r\nexport type {\r\n SkraFileRejection,\r\n SkraFileRejectionReason,\r\n} from '../file-helpers/file-partition';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/** True when a drag carries files from the OS — not text, not a link, not an in-page node. */\r\nfunction carriesFiles(event: DragEvent): boolean {\r\n const types = event.dataTransfer?.types;\r\n return !!types && Array.from(types).includes('Files');\r\n}\r\n\r\n/**\r\n * `input[type=\"file\"][skraFileInput]` — the native file control (spec\r\n * `component-file-upload-spec.md`; ADR 0056 Group B). A Component-on-a-native-host\r\n * (ADR 040): `<input>` is void, so `template: ''`, and `file-input.scss` is scoped to the\r\n * host by Emulated encapsulation — the box from `comp.field.*`, the user agent's\r\n * `::file-selector-button` painted from `comp.field.file.*` (ADR 0056 B1–B5).\r\n *\r\n * **No inputs.** Every constraint is a NATIVE attribute on the consumer's own host —\r\n * `accept`, `multiple`, `capture`, `required`, `disabled`, `name`, `webkitdirectory`\r\n * (native-attr-first, Iron Boundary #9). Skra reads them at the moment of a selection; it\r\n * never mirrors them.\r\n *\r\n * **Agnostic value (ADR 037).** The selection is REPORTED, never held: `filesChange` carries\r\n * the normalised files, `filesRejected` what the normalisation turned down. Native\r\n * `(change)` keeps working and reports the RAW selection; `filesChange` is the normalised one.\r\n *\r\n * **Normalisation** — Skra enforces exactly what the platform's own picker enforces, on\r\n * every path, and nothing more (size / count caps / duplicates are product policy):\r\n *\r\n * | Rule | Picker (`change`) | Drop (`drop` on the host) |\r\n * | --- | --- | --- |\r\n * | `accept` mismatch → `type` | possible (Windows \"All files\", Android) | the browser applies no `accept` to drops |\r\n * | >1 file without `multiple` → `count` | impossible | possible — ALL rejected |\r\n * | a directory → `directory` | impossible | possible |\r\n * | assignment | `input.files` left as the platform set it | `input.files` = the ACCEPTED files, then `input` + `change` are dispatched |\r\n *\r\n * A drop where nothing is accepted leaves the existing selection untouched and emits only\r\n * `filesRejected` — like a cancelled picker, it is not a change.\r\n *\r\n * **Field wiring (ADR 013 §3.7)** — the `skraInput` wiring verbatim: optional\r\n * `SkraFieldContext`; `id` / `disabled` written from guarded `effect()`s so a standalone\r\n * consumer's own attributes survive; `aria-describedby` / `aria-invalid` / `aria-required`\r\n * host bindings. Readonly: the native `readonly` attribute does not apply to `type=\"file\"`\r\n * (HTML) and `aria-readonly` is not exposed for its `button` role (G-4, measured), so it is\r\n * `aria-disabled=\"true\"` — the focusable soft-disable — plus a behaviour guard that blocks the\r\n * picker (`click`, keys other than `Tab`) and drops.\r\n *\r\n * **Known limitation (G-4, measured in Chromium):** \"required\" cannot reach assistive\r\n * technology on this control — neither `aria-required` (kept: harmless, and the field's\r\n * contract) nor native `required` is exposed for the `button` role. Say \"required\" in visible\r\n * text (the label or the hint) as well.\r\n *\r\n * **Inside `<skra-file-upload>`** (ADR 0056 Group D) the composite's context is injected:\r\n * the host reflects `data-skra-in-upload` (ADR 027 §3.9b) and its own stylesheet makes it a\r\n * transparent overlay over the painted face (`opacity: 0` only — D2); its name becomes\r\n * \"field label + visible action text\" via `aria-labelledby` (D4, WCAG 2.5.3) and the\r\n * composite's status region joins its description.\r\n *\r\n * <skra-field>\r\n * <label skraLabelFor>Session recording</label>\r\n * <input skraFileInput type=\"file\" accept=\"video/*\" #picker (filesChange)=\"onFiles($event)\" />\r\n * </skra-field>\r\n */\r\n@Component({\r\n selector: 'input[type=\"file\"][skraFileInput]',\r\n standalone: true,\r\n // Void host — no <ng-content>. See ADR 040 §2.\r\n template: '',\r\n styleUrl: './file-input.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // ARIA relationships — Skra-owned, present only while a field / the composite cascades them.\r\n '[attr.aria-describedby]': 'describedBy()',\r\n '[attr.aria-labelledby]': 'labelledBy()',\r\n '[attr.aria-invalid]': 'context?.hasError() ? \"true\" : null',\r\n '[attr.aria-required]': 'context?.isRequired() ? \"true\" : null',\r\n // Readonly → `aria-disabled` (spec Q-4's fallback, taken 2026-10-31 on the G-4\r\n // measurement): native `readonly` does not apply to type=\"file\", and `aria-readonly` is\r\n // not exposed for the role a file input has (`button`) — a screen reader heard nothing.\r\n // `aria-disabled` alone is the sanctioned soft-disable (boundary #9 exception): the\r\n // control stays focusable, AT hears \"unavailable\", the guard below makes it true. Never\r\n // alongside native `disabled`, which already says it.\r\n '[attr.aria-disabled]': 'softDisabled() ? \"true\" : null',\r\n // ADR 027 §3.9a — a Pointer state with no pseudo-class (`:drop()` never shipped).\r\n '[attr.data-skra-dragover]': 'dragOver() ? \"\" : null',\r\n // ADR 027 §3.9b — structural placement marker, static for the instance's lifetime.\r\n '[attr.data-skra-in-upload]': 'inUpload ? \"\" : null',\r\n '(change)': 'onChange()',\r\n '(click)': 'blockWhenReadonly($event)',\r\n '(keydown)': 'blockKeyWhenReadonly($event)',\r\n '(dragenter)': 'onDragEnter($event)',\r\n '(dragover)': 'onDragOver($event)',\r\n '(dragleave)': 'onDragLeave()',\r\n '(drop)': 'onDrop($event)',\r\n '(dragend)': 'resetDrag()',\r\n },\r\n})\r\nexport class SkraFileInput {\r\n private readonly el = inject<ElementRef<HTMLInputElement>>(ElementRef);\r\n readonly context = inject(SkraFieldContext, { optional: true });\r\n private readonly upload = inject(SkraFileUploadContext, { optional: true });\r\n\r\n /** User picked or dropped files. Fires on user interaction only, after normalisation. */\r\n readonly filesChange = output<readonly File[]>();\r\n\r\n /** Files the normalisation rejected. Fires only when at least one was rejected. */\r\n readonly filesRejected = output<readonly SkraFileRejection[]>();\r\n\r\n protected readonly inUpload = this.upload !== null;\r\n protected readonly dragOver = signal(false);\r\n\r\n // dragenter / dragleave also fire when the pointer crosses into the user agent's own\r\n // button inside the control (retargeted to the host), and Safari reports a null\r\n // `relatedTarget` on every dragleave — so a depth counter, not relatedTarget, decides\r\n // when the drag has really left (spec G-5).\r\n private dragDepth = 0;\r\n\r\n protected readonly softDisabled = computed(\r\n () => !!this.context?.isReadonly() && !this.context.isDisabled(),\r\n );\r\n\r\n protected readonly describedBy = computed(() => {\r\n const ids = [this.context?.describedByIds(), this.upload?.statusId].filter(\r\n Boolean,\r\n );\r\n return ids.length ? ids.join(' ') : null;\r\n });\r\n\r\n // ADR 0056 D4 — field label first, the face's action text second; the action alone when\r\n // there is no field. Outside the composite the name is the consumer's `<label>` (Path 1).\r\n protected readonly labelledBy = computed(() => {\r\n if (!this.upload) return null;\r\n return [this.context?.labelId(), this.upload.actionId]\r\n .filter(Boolean)\r\n .join(' ');\r\n });\r\n\r\n constructor() {\r\n const el = this.el.nativeElement;\r\n\r\n // Field-cascaded native properties — only bound when a field is present, so a\r\n // standalone consumer keeps full control of its own `id` / `disabled` (ADR 013 §3.7).\r\n if (this.context) {\r\n const ctx = this.context;\r\n effect(() => {\r\n el.id = ctx.fieldId();\r\n });\r\n effect(() => {\r\n el.disabled = ctx.isDisabled();\r\n });\r\n }\r\n\r\n // Dev-only: inside the composite, `aria-labelledby` names the control and OVERRIDES a\r\n // `<label for>` — so outside <skra-field> a consumer's own label would vanish from the\r\n // name. A read of the rendered control, never a write.\r\n if (\r\n this.upload &&\r\n !this.context &&\r\n (typeof ngDevMode === 'undefined' || ngDevMode)\r\n ) {\r\n afterNextRender(() => {\r\n if (el.labels?.length) {\r\n console.warn(\r\n '[skraFileInput] inside <skra-file-upload> without <skra-field>, the control is named by ' +\r\n 'its visible action alone (aria-labelledby, ADR 0056 D4) — which overrides your ' +\r\n '<label for>. Wrap it in <skra-field> with label[skraLabelFor] to get \"label + action\".',\r\n );\r\n }\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Reset the native selection (`value = ''`) so the same file can be picked again — the\r\n * queue model (`filesChange` → enqueue → `clear()`). Programmatic: emits nothing.\r\n * Reach it through a template reference: `#picker` on the host resolves to this component.\r\n */\r\n clear(): void {\r\n this.el.nativeElement.value = '';\r\n }\r\n\r\n private get blocked(): boolean {\r\n return this.el.nativeElement.disabled || !!this.context?.isReadonly();\r\n }\r\n\r\n /**\r\n * The native constraints, read at selection time. A `webkitdirectory` picker hands over\r\n * EVERY file of the chosen folder whether or not `multiple` is set, so it counts as\r\n * multiple — otherwise each folder pick would be rejected whole as `count`.\r\n */\r\n private constraints() {\r\n const el = this.el.nativeElement;\r\n return { accept: el.accept, multiple: el.multiple || el.webkitdirectory };\r\n }\r\n\r\n /**\r\n * The picker path — and the drop path's own dispatched `change`, already normalised.\r\n *\r\n * Order is part of the contract, the same on both paths: `filesChange` FIRST, then\r\n * `filesRejected`. A consumer that clears its error on a new selection and sets it on a\r\n * rejection then ends on the rejection message, not on a cleared one. A selection where\r\n * EVERY file was rejected emits no `filesChange` at all (like a fully rejected drop): it\r\n * changed nothing the consumer can use. An empty selection with no rejection (a picker\r\n * that reports a cleared selection) still emits `filesChange([])`.\r\n */\r\n protected onChange(): void {\r\n const el = this.el.nativeElement;\r\n const { accepted, rejected } = partitionFiles(\r\n Array.from(el.files ?? [], (file) => ({ file, isDirectory: false })),\r\n this.constraints(),\r\n );\r\n if (accepted.length || !rejected.length) this.filesChange.emit(accepted);\r\n if (rejected.length) this.filesRejected.emit(rejected);\r\n }\r\n\r\n /** Readonly: `preventDefault` on `click` keeps the picker closed, for pointer and keyboard alike. */\r\n protected blockWhenReadonly(event: Event): void {\r\n if (this.context?.isReadonly()) event.preventDefault();\r\n }\r\n\r\n /** Readonly: block keyboard activation; let `Tab` through. */\r\n protected blockKeyWhenReadonly(event: KeyboardEvent): void {\r\n if (this.context?.isReadonly() && event.key !== 'Tab') {\r\n event.preventDefault();\r\n }\r\n }\r\n\r\n protected onDragEnter(event: DragEvent): void {\r\n if (!carriesFiles(event) || this.blocked) return;\r\n event.preventDefault();\r\n this.dragDepth += 1;\r\n this.dragOver.set(true);\r\n }\r\n\r\n protected onDragOver(event: DragEvent): void {\r\n if (!carriesFiles(event)) return;\r\n // Always cancelled for a file drag: on a blocked control that is what stops the user\r\n // agent's own drop handling (which would assign the files); `dropEffect` tells the\r\n // user why nothing will happen.\r\n event.preventDefault();\r\n if (event.dataTransfer) {\r\n event.dataTransfer.dropEffect = this.blocked ? 'none' : 'copy';\r\n }\r\n if (!this.blocked) {\r\n // A dragover with no counted dragenter (the control became enabled mid-drag) still\r\n // owes the leave that clears it.\r\n if (this.dragDepth === 0) this.dragDepth = 1;\r\n this.dragOver.set(true);\r\n }\r\n }\r\n\r\n protected onDragLeave(): void {\r\n if (this.dragDepth === 0) return;\r\n this.dragDepth -= 1;\r\n if (this.dragDepth === 0) this.dragOver.set(false);\r\n }\r\n\r\n protected resetDrag(): void {\r\n this.dragDepth = 0;\r\n this.dragOver.set(false);\r\n }\r\n\r\n /** The drop path — normalise, then assign the ACCEPTED files and replay the native events. */\r\n protected onDrop(event: DragEvent): void {\r\n if (!carriesFiles(event)) return;\r\n event.preventDefault();\r\n this.resetDrag();\r\n if (this.blocked || !event.dataTransfer) return;\r\n\r\n const el = this.el.nativeElement;\r\n const { accepted, rejected } = partitionFiles(\r\n this.candidatesOf(event.dataTransfer),\r\n this.constraints(),\r\n );\r\n\r\n if (accepted.length) {\r\n const transfer = new DataTransfer();\r\n for (const file of accepted) transfer.items.add(file);\r\n el.files = transfer.files;\r\n // The native event stream stays the one source of truth: consumers bound through\r\n // `(change)`, `[formControl]` or `[(ngModel)]` see a drop exactly like a pick, and\r\n // `onChange()` emits `filesChange` once, from the same place for both paths.\r\n el.dispatchEvent(new Event('input', { bubbles: true }));\r\n el.dispatchEvent(new Event('change', { bubbles: true }));\r\n }\r\n // Last, as on the picker path (see onChange).\r\n if (rejected.length) this.filesRejected.emit(rejected);\r\n }\r\n\r\n /**\r\n * Directory detection has to happen INSIDE the `drop` handler: `webkitGetAsEntry()` is the\r\n * only cross-engine signal (a dropped folder arrives as a `File` too), and the item list\r\n * is emptied once the event returns.\r\n */\r\n private candidatesOf(transfer: DataTransfer): SkraFileCandidate[] {\r\n const items = transfer.items\r\n ? Array.from(transfer.items).filter((i) => i.kind === 'file')\r\n : [];\r\n if (!items.length) {\r\n return Array.from(transfer.files, (file) => ({\r\n file,\r\n isDirectory: false,\r\n }));\r\n }\r\n const candidates: SkraFileCandidate[] = [];\r\n for (const item of items) {\r\n const file = item.getAsFile();\r\n if (!file) continue;\r\n const entry =\r\n typeof item.webkitGetAsEntry === 'function'\r\n ? item.webkitGetAsEntry()\r\n : null;\r\n candidates.push({ file, isDirectory: !!entry?.isDirectory });\r\n }\r\n return candidates;\r\n }\r\n}\r\n","import { DOCUMENT, Injectable, inject } from '@angular/core';\r\n\r\n/**\r\n * Internal — NOT part of the public barrel. The page-navigation guard of the FileUpload\r\n * family (spec Q-3, architect-reviewed 2026-10-31: spec-level, not an ADR).\r\n *\r\n * A file dropped a few pixels OUTSIDE a drop zone makes the browser navigate to it — midway\r\n * through a multi-GB upload, that destroys the session. While at least one\r\n * `<skra-file-upload>` is mounted, this cancels `dragover` / `drop` on the document, and only\r\n * for drags that:\r\n * - carry `Files` (text, links and in-page drags are never touched);\r\n * - nothing nearer has already handled (`defaultPrevented` — every drop target, including\r\n * `input[skraFileInput]`, cancels the events it accepts);\r\n * - do not land on a target that accepts files natively: ANY `input[type=\"file\"]` (Skra's or\r\n * not) and editable content keep their own drop behaviour.\r\n *\r\n * It is the library's FIRST document-level listener, so the rules are binding here: scoped\r\n * exactly as above, ref-counted (installed once for any number of instances, removed with the\r\n * last), browser-only (installed from `afterNextRender`, so never under SSR). A second\r\n * component needing one lifts these rules into an ADR. react-dropzone ships the same default\r\n * (`preventDropOnDocument`).\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class SkraFileDropGuard {\r\n private readonly doc = inject(DOCUMENT);\r\n private holders = 0;\r\n\r\n // Cancel ONLY — no `dropEffect` write. Cancelling `dragover` + `drop` is what stops the\r\n // navigation; writing `dropEffect = 'none'` here would also silently kill a consumer's own\r\n // page-wide drop target on `window` (or a later `document` listener) that cancels without\r\n // setting `dropEffect` itself — the browser would never fire its `drop` (review 2026-11-01).\r\n private readonly onDragOver = (event: DragEvent): void => {\r\n if (this.guards(event)) event.preventDefault();\r\n };\r\n\r\n private readonly onDrop = (event: DragEvent): void => {\r\n if (this.guards(event)) event.preventDefault();\r\n };\r\n\r\n /** One mounted composite more. Installs the listeners on the first. */\r\n acquire(): void {\r\n this.holders += 1;\r\n if (this.holders > 1) return;\r\n this.doc.addEventListener('dragover', this.onDragOver);\r\n this.doc.addEventListener('drop', this.onDrop);\r\n }\r\n\r\n /** One mounted composite fewer. Removes the listeners with the last. */\r\n release(): void {\r\n if (this.holders === 0) return;\r\n this.holders -= 1;\r\n if (this.holders > 0) return;\r\n this.doc.removeEventListener('dragover', this.onDragOver);\r\n this.doc.removeEventListener('drop', this.onDrop);\r\n }\r\n\r\n private guards(event: DragEvent): boolean {\r\n if (event.defaultPrevented) return false;\r\n const types = event.dataTransfer?.types;\r\n if (!types || !Array.from(types).includes('Files')) return false;\r\n const target = event.target as\r\n | (Partial<Pick<Element, 'closest'>> & { isContentEditable?: boolean })\r\n | null;\r\n if (target?.closest?.('input[type=\"file\"]')) return false;\r\n if (target?.isContentEditable) return false;\r\n return true;\r\n }\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n DestroyRef,\r\n ElementRef,\r\n ViewEncapsulation,\r\n afterNextRender,\r\n computed,\r\n contentChild,\r\n contentChildren,\r\n effect,\r\n inject,\r\n} from '@angular/core';\r\nimport { SkraFileDropGuard } from './file-drop-guard';\r\nimport { SkraFileInput } from '../file-input/file-input';\r\nimport {\r\n SkraFileUploadAction,\r\n SkraFileUploadInstruction,\r\n SkraFileUploadStart,\r\n SkraFileUploadStatus,\r\n} from '../file-upload.directives';\r\nimport { SkraFileUploadContext } from './file-upload-context';\r\n\r\ndeclare const ngDevMode: boolean | undefined;\r\n\r\n/**\r\n * `<skra-file-upload>` — the optional enhancement over a projected `input[skraFileInput]`\r\n * (spec `component-file-upload-spec.md`; ADR 0056 Group D). It paints a localisable face —\r\n * the action and the instruction in the PAGE's language, from tokens — enlarges the control\r\n * into a drop zone, and hosts the live selection-status region.\r\n *\r\n * Why it exists: the native control's two strings (\"Choose File\" / \"No file chosen\") come\r\n * from the browser's UI language, not the page's `lang`, and no CSS or attribute can replace\r\n * them (ADR 0056 §1.6). The native control stays THE control (D2): transparent\r\n * (`opacity: 0`, its own stylesheet, switched on by this component's context), covering the\r\n * whole face, it remains the focus target, the pointer target, the drop target and the node\r\n * assistive technology reads — so `required`, `aria-invalid`, the validation bubble, label\r\n * activation, form submission and the iOS camera / library sheet all keep working.\r\n *\r\n * **State-READING** (ADR 027 §3.8, ADR 055): no inputs, no outputs; every state it paints —\r\n * hover, focus-visible, drag-over, disabled, readonly, invalid — is read from the projected\r\n * control through `:has()`. It owns no state, so it mirrors no ARIA.\r\n *\r\n * **Layout follows content (ADR 020).** No `[skra-file-upload-instruction]` → a compact,\r\n * field-like row (`[icon] [action] status`); with one → the drop-zone layout (stacked,\r\n * centred, dashed). Both accept drops. There is no look input (skin philosophy).\r\n *\r\n * **Never project interactive content** into it — the transparent control covers the whole\r\n * face and swallows the clicks (D3). The file list is a SIBLING.\r\n *\r\n * **Page-navigation guard.** While one is mounted, a FILE drag dropped outside every drop\r\n * target is cancelled instead of navigating the page to the file (spec Q-3; text / link\r\n * drags, native file inputs and editable content are untouched).\r\n *\r\n * <skra-field [hasError]=\"!!error()\">\r\n * <label skraLabelFor>Session recording</label>\r\n * <skra-file-upload>\r\n * <span skra-file-upload-action>Choose a video</span>\r\n * <span skra-file-upload-instruction>or drag it here</span>\r\n * <span skra-file-upload-status>{{ summary() }}</span>\r\n * <input skraFileInput type=\"file\" accept=\"video/*\" (filesChange)=\"onFiles($event)\" />\r\n * </skra-file-upload>\r\n * <skra-error>{{ error() }}</skra-error>\r\n * </skra-field>\r\n */\r\n@Component({\r\n selector: 'skra-file-upload',\r\n standalone: true,\r\n templateUrl: './file-upload.html',\r\n styleUrl: './file-upload.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n providers: [SkraFileUploadContext],\r\n host: {\r\n // Slot presence (ADR 020 / ADR 027 §3.6 — exempt from the State Surface).\r\n '[attr.data-skra-has-start]': 'hasStart() ? \"\" : null',\r\n '[attr.data-skra-has-instruction]': 'hasInstruction() ? \"\" : null',\r\n '[attr.data-skra-has-status]': 'hasStatus() ? \"\" : null',\r\n },\r\n})\r\nexport class SkraFileUpload {\r\n protected readonly ctx = inject(SkraFileUploadContext);\r\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\r\n\r\n // `descendants: false` — projection takes top-level content only, so detection must too\r\n // (ADR 020: a slot marker nested deeper is never projected and must not render a wrapper).\r\n private readonly start = contentChild(SkraFileUploadStart, {\r\n descendants: false,\r\n });\r\n private readonly action = contentChild(SkraFileUploadAction, {\r\n descendants: false,\r\n });\r\n private readonly instruction = contentChild(SkraFileUploadInstruction, {\r\n descendants: false,\r\n });\r\n private readonly status = contentChild(SkraFileUploadStatus, {\r\n descendants: false,\r\n });\r\n // Direct children only (the projection slot takes nothing else) vs anywhere inside.\r\n private readonly inputs = contentChildren(SkraFileInput);\r\n private readonly nestedInputs = contentChildren(SkraFileInput, {\r\n descendants: true,\r\n });\r\n\r\n protected readonly hasStart = computed(() => !!this.start());\r\n protected readonly hasInstruction = computed(() => !!this.instruction());\r\n protected readonly hasStatus = computed(() => !!this.status());\r\n\r\n constructor() {\r\n // The page-navigation guard (spec Q-3): a missed drop must not navigate away from a\r\n // multi-GB upload. Browser-only by construction — `afterNextRender` never runs under SSR\r\n // — and ref-counted across every mounted composite.\r\n const guard = inject(SkraFileDropGuard);\r\n const destroyRef = inject(DestroyRef);\r\n afterNextRender(() => {\r\n guard.acquire();\r\n destroyRef.onDestroy(() => guard.release());\r\n });\r\n\r\n if (typeof ngDevMode === 'undefined' || ngDevMode) {\r\n effect(() => this.warnMisuse());\r\n afterNextRender(() => this.warnInteractiveFace());\r\n }\r\n }\r\n\r\n /**\r\n * Dev-only, ADR 0056 D3: the face is paint. Anything interactive projected into it sits\r\n * UNDER the transparent control, so the control swallows its clicks — and inside the\r\n * `aria-hidden` face it is hidden from assistive technology while still focusable. A read of\r\n * the rendered face, never a write.\r\n */\r\n private warnInteractiveFace(): void {\r\n const face = this.host.nativeElement.querySelector(\r\n '.skra-file-upload-face',\r\n );\r\n const offender = face?.querySelector(\r\n 'a[href], button, input, select, textarea, [tabindex], [contenteditable]',\r\n );\r\n if (offender) {\r\n console.error(\r\n `[skra-file-upload] interactive content (<${offender.tagName.toLowerCase()}>) is ` +\r\n 'projected into the face. The transparent control covers the whole face and swallows ' +\r\n 'its clicks, and the face is aria-hidden (ADR 0056 D3). Put row actions in a SIBLING ' +\r\n 'list (ul[skraStack] of li[skraFileItem]).',\r\n );\r\n }\r\n }\r\n\r\n /** Dev-only: the composite cannot work without exactly one direct-child control and an action. */\r\n private warnMisuse(): void {\r\n const direct = this.inputs().length;\r\n const all = this.nestedInputs().length;\r\n if (all === 0) {\r\n console.error(\r\n '[skra-file-upload] needs a direct-child <input type=\"file\" skraFileInput> — it is the ' +\r\n 'control; the component only paints a face over it (ADR 0056 Group D). Import ' +\r\n 'SkraFileInput and project the input as a direct child.',\r\n );\r\n } else if (direct !== all) {\r\n console.error(\r\n '[skra-file-upload] the input[skraFileInput] must be a DIRECT child — wrapped in another ' +\r\n 'element it is never projected, and nothing covers the face.',\r\n );\r\n } else if (direct > 1) {\r\n console.error(\r\n '[skra-file-upload] takes exactly ONE input[skraFileInput]; use `multiple` on it for ' +\r\n 'several files.',\r\n );\r\n }\r\n if (!this.action()) {\r\n console.error(\r\n '[skra-file-upload] needs a [skra-file-upload-action] (e.g. <span skra-file-upload-action>' +\r\n 'Choose a video</span>) — it is the visible action and half of the control’s accessible ' +\r\n 'name (ADR 0056 D4). Import SkraFileUploadAction so it can be detected.',\r\n );\r\n }\r\n }\r\n}\r\n","<!--\r\n The FACE (ADR 0056 D3) — paint, not a widget: aria-hidden, nothing focusable. The native\r\n control projected below covers all of it (D2) and is the only thing a user or AT operates.\r\n-->\r\n<span class=\"skra-file-upload-face\" aria-hidden=\"true\">\r\n @if (hasStart()) {\r\n <span class=\"skra-file-upload-icon\"\r\n ><ng-content select=\"[skra-start]\"\r\n /></span>\r\n }\r\n <!-- Referenced by the control's aria-labelledby (D4): the visible action text IS in the name. -->\r\n <span class=\"skra-file-upload-action\" [id]=\"ctx.actionId\"\r\n ><ng-content select=\"[skra-file-upload-action]\"\r\n /></span>\r\n @if (hasInstruction()) {\r\n <span class=\"skra-file-upload-instruction\"\r\n ><ng-content select=\"[skra-file-upload-instruction]\"\r\n /></span>\r\n }\r\n</span>\r\n<!--\r\n ALWAYS rendered: a live region must exist before its content changes, or the first change is\r\n not announced. Outside the aria-hidden face (D3's one exception) and linked to the control as a\r\n description. Role only — the implicit `status` politeness, no explicit aria-live (ADR 0052).\r\n-->\r\n<span class=\"skra-file-upload-status\" role=\"status\" [id]=\"ctx.statusId\"\r\n ><ng-content select=\"[skra-file-upload-status]\"\r\n/></span>\r\n<ng-content select=\"input[skraFileInput]\" />\r\n","/** A file name split for middle truncation: the stem may shrink, the extension never does. */\r\nexport interface SkraFileNameParts {\r\n readonly stem: string;\r\n readonly ext: string;\r\n}\r\n\r\n/**\r\n * Internal — NOT part of the public barrel. Split a file name at its LAST dot, for display.\r\n *\r\n * - `clip.final.mp4` → `clip.final` + `.mp4` (only the last dot separates);\r\n * - `.env` → no extension (a dotfile is all name — the dot is at index 0);\r\n * - `README`, `x.` → no extension (none, or an empty one after a trailing dot).\r\n *\r\n * Purely visual: the row also renders the WHOLE name for assistive technology, so the split\r\n * (and the ellipsis) is never heard.\r\n */\r\nexport function splitFileName(name: string): SkraFileNameParts {\r\n const dot = name.lastIndexOf('.');\r\n if (dot <= 0 || dot === name.length - 1) return { stem: name, ext: '' };\r\n return { stem: name.slice(0, dot), ext: name.slice(dot) };\r\n}\r\n","import {\r\n ChangeDetectionStrategy,\r\n Component,\r\n ViewEncapsulation,\r\n computed,\r\n contentChild,\r\n input,\r\n} from '@angular/core';\r\nimport { skraFormatFileSize } from '../file-helpers/file-helpers';\r\nimport { splitFileName } from '../file-helpers/file-name';\r\nimport {\r\n SkraFileItemDetail,\r\n SkraFileItemEnd,\r\n SkraFileItemError,\r\n SkraFileItemStart,\r\n} from '../file-upload.directives';\r\n\r\n/**\r\n * `li[skraFileItem]` — a display row for ONE consumer-owned file (spec\r\n * `component-file-upload-spec.md`). A Component-on-a-native-host (ADR 012 / ADR 040): the\r\n * `<li>` keeps its list-item semantics inside the consumer's `ul[skraStack]`.\r\n *\r\n * Separate from `<skra-file-upload>` by SRP: a row outlives the selection (it tracks an\r\n * upload), its source of truth is the consumer's queue — not `input.files` — and it is a\r\n * display list item, not a form control. **Skra never uploads**: progress, retry, cancel and\r\n * removal are the consumer's, projected into the row's slots.\r\n *\r\n * - **Name**, middle-truncated with the extension always visible — pure CSS, no measurement.\r\n * The visual split is `aria-hidden`; an `[skra-sr-only]` copy carries the whole name.\r\n * - **Size** — `skraFormatFileSize(size, locale)`: SI units, `Intl` short labels, the\r\n * `locale` input or the host default (the ADR 0050 §5 precedent).\r\n * - **Invalid is READ, never owned** (ADR 027 §3.8, spec Q-7): the row paints\r\n * `data-skra-validation=\"invalid\"` only while `[skra-file-item-error]` text is projected, so\r\n * the colour never appears without the words (WCAG 1.4.1 by construction). No `aria-invalid`\r\n * — no role an `<li>` holds supports it.\r\n *\r\n * <ul skraStack>\r\n * @for (u of uploads(); track u.id) {\r\n * <li skraFileItem [name]=\"u.file.name\" [size]=\"u.file.size\" locale=\"pl-PL\">\r\n * <progress skraProgress skra-file-item-detail [value]=\"u.sent\" [max]=\"u.file.size\"\r\n * [attr.aria-label]=\"'Uploading ' + u.file.name\"></progress>\r\n * @if (u.error) { <span skra-file-item-error>{{ u.error }}</span> }\r\n * <button skraButton skra-end emphasis=\"low\" (click)=\"cancel(u)\">\r\n * Cancel<span skra-sr-only> {{ u.file.name }}</span>\r\n * </button>\r\n * </li>\r\n * }\r\n * </ul>\r\n */\r\n@Component({\r\n selector: 'li[skraFileItem]',\r\n standalone: true,\r\n templateUrl: './file-item.html',\r\n styleUrl: './file-item.scss',\r\n changeDetection: ChangeDetectionStrategy.OnPush,\r\n encapsulation: ViewEncapsulation.Emulated,\r\n host: {\r\n // Slot presence (ADR 020 / ADR 027 §3.6 — exempt).\r\n '[attr.data-skra-has-start]': 'hasStart() ? \"\" : null',\r\n '[attr.data-skra-has-detail]': 'hasDetail() ? \"\" : null',\r\n '[attr.data-skra-has-end]': 'hasEnd() ? \"\" : null',\r\n // Validation READ from the error slot (ADR 027 §3.8) — the canonical value, never\r\n // `data-skra-has-error` (ADR 027 iron boundary).\r\n '[attr.data-skra-validation]': 'hasError() ? \"invalid\" : null',\r\n },\r\n})\r\nexport class SkraFileItem {\r\n /** The file name, shown as stem + extension. */\r\n readonly name = input.required<string>();\r\n\r\n /** Size in bytes, formatted for display. `undefined` → no size shown. */\r\n readonly size = input<number | undefined>(undefined);\r\n\r\n /** `Intl` locale for the size. `undefined` → the host default (ADR 0050 §5 precedent). */\r\n readonly locale = input<string | undefined>(undefined);\r\n\r\n // `descendants: false` — `<ng-content select>` projects only TOP-LEVEL content, so detection\r\n // must look no deeper: an icon marked `[skra-start]` inside an end-slot button would\r\n // otherwise report a start slot and render an empty wrapper (ADR 020).\r\n private readonly start = contentChild(SkraFileItemStart, {\r\n descendants: false,\r\n });\r\n private readonly detail = contentChild(SkraFileItemDetail, {\r\n descendants: false,\r\n });\r\n private readonly error = contentChild(SkraFileItemError, {\r\n descendants: false,\r\n });\r\n private readonly end = contentChild(SkraFileItemEnd, { descendants: false });\r\n\r\n protected readonly hasStart = computed(() => !!this.start());\r\n protected readonly hasDetail = computed(() => !!this.detail());\r\n protected readonly hasError = computed(() => !!this.error());\r\n protected readonly hasEnd = computed(() => !!this.end());\r\n\r\n protected readonly parts = computed(() => splitFileName(this.name()));\r\n\r\n // A size that cannot exist is shown as no size, not as an exception in the template:\r\n // the row is display, and the helper's RangeError is for the caller who computes sizes.\r\n protected readonly sizeLabel = computed(() => {\r\n const bytes = this.size();\r\n if (bytes === undefined || !Number.isFinite(bytes) || bytes < 0) return '';\r\n return skraFormatFileSize(bytes, this.locale());\r\n });\r\n}\r\n","@if (hasStart()) {\r\n<span class=\"skra-file-item-start\"><ng-content select=\"[skra-start]\" /></span>\r\n}\r\n<span class=\"skra-file-item-body\">\r\n <!--\r\n The name, middle-truncated with the extension always visible. The split pieces are\r\n aria-hidden; the whole name is read from the sr-only copy, so a screen reader never hears\r\n the split or the ellipsis. `dir=\"auto\"` lets an RTL name order its own pieces.\r\n -->\r\n <span class=\"skra-file-item-name\" dir=\"auto\">\r\n <span class=\"skra-file-item-stem\" aria-hidden=\"true\"\r\n >{{ parts().stem }}</span\r\n >\r\n @if (parts().ext) {\r\n <span class=\"skra-file-item-ext\" aria-hidden=\"true\">{{ parts().ext }}</span>\r\n }\r\n <span skra-sr-only>{{ name() }}</span>\r\n </span>\r\n @if (sizeLabel()) {\r\n <span class=\"skra-file-item-meta\">{{ sizeLabel() }}</span>\r\n } @if (hasDetail()) {\r\n <span class=\"skra-file-item-detail\"\r\n ><ng-content select=\"[skra-file-item-detail]\"\r\n /></span>\r\n } @if (hasError()) {\r\n <span class=\"skra-file-item-error\"\r\n ><ng-content select=\"[skra-file-item-error]\"\r\n /></span>\r\n }\r\n</span>\r\n@if (hasEnd()) {\r\n<span class=\"skra-file-item-end\"><ng-content select=\"[skra-end]\" /></span>\r\n}\r\n","// Public API for @skra/ui/file-upload — the FileUpload family (spec\r\n// adr/specs/component-file-upload-spec.md; ADR 0056 Groups B + D).\r\nexport * from './lib/file-upload.directives';\r\nexport * from './lib/file-helpers/file-helpers';\r\nexport * from './lib/file-input/file-input';\r\nexport * from './lib/file-upload/file-upload';\r\nexport * from './lib/file-item/file-item';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
|
@@ -114,7 +114,7 @@ class SkraToast {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraToast, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
117
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraToast, isStandalone: true, selector: "skra-toast", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, emphasis: { classPropertyName: "emphasis", publicName: "emphasis", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { listeners: { "mouseenter": "pause()", "mouseleave": "resume()", "focusin": "pause()", "focusout": "resume()" }, properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-emphasis": "emphasis()", "attr.data-skra-has-icon": "hasIcon() ? \"\" : null" } }, queries: [{ propertyName: "iconSlot", first: true, predicate: SkraToastIcon, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "contentRef", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-toast-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-toast-dismiss:hover{opacity:.7}}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
117
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SkraToast, isStandalone: true, selector: "skra-toast", inputs: { intent: { classPropertyName: "intent", publicName: "intent", isSignal: true, isRequired: false, transformFunction: null }, emphasis: { classPropertyName: "emphasis", publicName: "emphasis", isSignal: true, isRequired: false, transformFunction: null }, live: { classPropertyName: "live", publicName: "live", isSignal: true, isRequired: false, transformFunction: null }, duration: { classPropertyName: "duration", publicName: "duration", isSignal: true, isRequired: false, transformFunction: null }, dismissible: { classPropertyName: "dismissible", publicName: "dismissible", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { dismissed: "dismissed" }, host: { listeners: { "mouseenter": "pause()", "mouseleave": "resume()", "focusin": "pause()", "focusout": "resume()" }, properties: { "attr.data-skra-intent": "intent()", "attr.data-skra-emphasis": "emphasis()", "attr.data-skra-has-icon": "hasIcon() ? \"\" : null" } }, queries: [{ propertyName: "iconSlot", first: true, predicate: SkraToastIcon, descendants: true, isSignal: true }], viewQueries: [{ propertyName: "contentRef", first: true, predicate: ["content"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-toast-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-neutral-high, var(--skra-sys-color-neutral-contrast) )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-neutral-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-info-high, var(--skra-sys-color-info-contrast) )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-info-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-success-high, var(--skra-sys-color-success-contrast) )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-success-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-warning-high, var(--skra-sys-color-warning-contrast) )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-warning-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-danger-high, var(--skra-sys-color-danger-contrast) )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-danger-medium, var(--skra-sys-color-focus-ring) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-toast-dismiss:hover{opacity:.7}}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
118
118
|
}
|
|
119
119
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SkraToast, decorators: [{
|
|
120
120
|
type: Component,
|
|
@@ -130,7 +130,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
130
130
|
'(mouseleave)': 'resume()',
|
|
131
131
|
'(focusin)': 'pause()',
|
|
132
132
|
'(focusout)': 'resume()',
|
|
133
|
-
}, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-toast-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-toast-dismiss:hover{opacity:.7}}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"] }]
|
|
133
|
+
}, template: "@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n", styles: ["@charset \"UTF-8\";:host{display:flex;align-items:flex-start;box-sizing:border-box;margin:0;gap:var(--skra-comp-toast-icon-gap);font-family:var(--skra-sys-typography-role-body-medium-font-family);font-size:var(--skra-sys-typography-role-body-medium-font-size);font-weight:var(--skra-sys-typography-role-body-medium-font-weight);line-height:var(--skra-sys-typography-role-body-medium-line-height);letter-spacing:var(--skra-sys-typography-role-body-medium-letter-spacing);background:var(--skra-comp-toast-background);color:var(--skra-comp-toast-foreground);border-color:var(--skra-comp-toast-border-color);border-width:var(--skra-comp-toast-border-width);border-style:var(--skra-comp-toast-border-style);border-radius:var(--skra-comp-toast-radius);padding-block:var(--skra-comp-toast-padding-block);padding-inline:var(--skra-comp-toast-padding-inline);box-shadow:var(--skra-comp-toast-shadow);opacity:1;transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@starting-style{:host{opacity:0}}:host([data-skra-emphasis=high]){--skra-comp-toast-border-width: 0}:host([data-skra-intent=neutral][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-high, var(--skra-sys-color-neutral-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-high, var(--skra-sys-color-neutral-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-neutral-high, var(--skra-sys-color-neutral-contrast) )}:host([data-skra-intent=neutral][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-neutral-medium, var(--skra-sys-color-neutral-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-neutral-medium, var(--skra-sys-color-neutral-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-neutral-medium, var(--skra-sys-color-neutral-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-neutral-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=info][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-high, var(--skra-sys-color-info-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-high, var(--skra-sys-color-info-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-info-high, var(--skra-sys-color-info-contrast) )}:host([data-skra-intent=info][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-info-medium, var(--skra-sys-color-info-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-info-medium, var(--skra-sys-color-info-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-info-medium, var(--skra-sys-color-info-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-info-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=success][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-high, var(--skra-sys-color-success-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-high, var(--skra-sys-color-success-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-success-high, var(--skra-sys-color-success-contrast) )}:host([data-skra-intent=success][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-success-medium, var(--skra-sys-color-success-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-success-medium, var(--skra-sys-color-success-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-success-medium, var(--skra-sys-color-success-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-success-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=warning][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-high, var(--skra-sys-color-warning-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-high, var(--skra-sys-color-warning-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-warning-high, var(--skra-sys-color-warning-contrast) )}:host([data-skra-intent=warning][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-warning-medium, var(--skra-sys-color-warning-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-warning-medium, var(--skra-sys-color-warning-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-warning-medium, var(--skra-sys-color-warning-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-warning-medium, var(--skra-sys-color-focus-ring) )}:host([data-skra-intent=danger][data-skra-emphasis=high]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-high, var(--skra-sys-color-danger-base) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-high, var(--skra-sys-color-danger-contrast) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-high, transparent );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-danger-high, var(--skra-sys-color-danger-contrast) )}:host([data-skra-intent=danger][data-skra-emphasis=medium]){--skra-comp-toast-background: var( --skra-comp-toast-background-danger-medium, var(--skra-sys-color-danger-soft) );--skra-comp-toast-foreground: var( --skra-comp-toast-foreground-danger-medium, var(--skra-sys-color-danger-strong) );--skra-comp-toast-border-color: var( --skra-comp-toast-border-color-danger-medium, var(--skra-sys-color-danger-border) );--skra-comp-toast-focus-ring-color: var( --skra-comp-toast-focus-ring-color-danger-medium, var(--skra-sys-color-focus-ring) )}.skra-toast-icon{display:inline-flex;flex-shrink:0;align-items:center;block-size:1lh;--skra-comp-icon-size: var(--skra-comp-toast-icon-size)}.skra-toast-content{flex:1 1 auto;min-inline-size:0}.skra-toast-dismiss{flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;inline-size:var(--skra-comp-toast-dismiss-size);block-size:var(--skra-comp-toast-dismiss-size);margin:0;padding:0;border:0;background:transparent;color:inherit;cursor:pointer;border-radius:var(--skra-comp-toast-radius);transition:opacity var(--skra-comp-toast-motion-duration) var(--skra-comp-toast-motion-easing)}@media(hover:hover)and (pointer:fine){.skra-toast-dismiss:hover{opacity:.7}}.skra-toast-dismiss:focus-visible{outline-style:solid;outline-color:var(--skra-comp-toast-focus-ring-color);outline-width:var(--skra-comp-toast-focus-ring-width);outline-offset:2px}.skra-toast-dismiss-glyph{font-size:1.25em;line-height:1}@media(prefers-reduced-motion:reduce){:host{transition-duration:0ms}.skra-toast-dismiss{transition:none}}\n"] }]
|
|
134
134
|
}], ctorParameters: () => [], propDecorators: { intent: [{ type: i0.Input, args: [{ isSignal: true, alias: "intent", required: false }] }], emphasis: [{ type: i0.Input, args: [{ isSignal: true, alias: "emphasis", required: false }] }], live: [{ type: i0.Input, args: [{ isSignal: true, alias: "live", required: false }] }], duration: [{ type: i0.Input, args: [{ isSignal: true, alias: "duration", required: false }] }], dismissible: [{ type: i0.Input, args: [{ isSignal: true, alias: "dismissible", required: false }] }], dismissed: [{ type: i0.Output, args: ["dismissed"] }], iconSlot: [{ type: i0.ContentChild, args: [i0.forwardRef(() => SkraToastIcon), { isSignal: true }] }], contentRef: [{ type: i0.ViewChild, args: ['content', { isSignal: true }] }] } });
|
|
135
135
|
|
|
136
136
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-toast.mjs","sources":["../../../../libs/ui/toast/src/lib/toast.directives.ts","../../../../libs/ui/toast/src/lib/toast/toast-announcer.ts","../../../../libs/ui/toast/src/lib/toast/toast.ts","../../../../libs/ui/toast/src/lib/toast/toast.html","../../../../libs/ui/toast/src/lib/toast/toast-region.ts","../../../../libs/ui/toast/src/lib/toast/toast-region.html","../../../../libs/ui/toast/src/skra-ui-toast.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n/**\n * Marker directive for the leading icon slot of `<skra-toast>`.\n * Detected via `contentChild` (ADR 020 Smart Slots v2.0) to toggle the icon\n * wrapper without emitting an empty DOM node. Feedback-local (not the button\n * lib's `[skra-start]`) to avoid a cross-lib marker dependency — mirrors\n * `[skra-alert-icon]` / `[skra-badge-icon]`.\n */\n@Directive({\n selector: '[skra-toast-icon]',\n standalone: true,\n})\nexport class SkraToastIcon {}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Politeness routed to the toast region's role-only announcer (ADR 0052 §7).\n * `off` never reaches the announcer (no announcement), so the seam only carries\n * the two announced levels.\n */\nexport type SkraToastPoliteness = 'polite' | 'assertive';\n\n/**\n * The ADR 0052 §7 announcement seam. Provided by `<skra-toast-region>` and injected\n * (optionally) by each projected `<skra-toast>`. The toast pushes its message text on\n * appearance; the region writes it into the matching PERSISTENT, role-only announcer\n * (`role=\"status\"` for polite / `role=\"alert\"` for assertive) — never a role/`aria-live`\n * on the ephemeral toast host. This is why a live region pre-exists the content it\n * announces (WCAG 4.1.3): the announcers are rendered from the region's first render.\n *\n * Narrow seam (like `SkraSelectPanel` / `SkraFieldContext`): the toast depends on the\n * interface, not the concrete region. Content-projected toasts inject from their DECLARED\n * parent element (= the region), the same DI mechanism as `SkraFieldContext` (ADR 013).\n */\nexport interface SkraToastAnnouncer {\n /** Announce `text` at the given politeness by writing it into the matching live region. */\n announce(text: string, politeness: SkraToastPoliteness): void;\n}\n\nexport const SKRA_TOAST_ANNOUNCER = new InjectionToken<SkraToastAnnouncer>(\n 'SKRA_TOAST_ANNOUNCER',\n);\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n ViewEncapsulation,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n output,\n viewChild,\n} from '@angular/core';\nimport { SkraToastIcon } from '../toast.directives';\nimport {\n SKRA_TOAST_ANNOUNCER,\n type SkraToastPoliteness,\n} from './toast-announcer';\n\n/**\n * ToastIntent — semantic feedback meaning (ADR 035 §3.1, downward subset). Excludes the\n * action intents `primary`/`secondary`. Same enum as Alert/Badge.\n */\nexport type ToastIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\n/** ToastEmphasis — `high` = filled, `medium` = soft. `low` deferred (ADR 035 §3.1). */\nexport type ToastEmphasis = 'high' | 'medium';\n\n/**\n * ToastLive — screen-reader announcement politeness (ADR 0052). For Toast the politeness\n * is routed to the REGION's announcer (ADR 0052 §7); it does NOT set a role on this host.\n * Default `polite` (toasts are always dynamically presented — ADR 0052 §4). `assertive`\n * for error toasts, set explicitly by the consumer — NEVER auto-derived from `intent`.\n */\nexport type ToastLive = 'off' | 'polite' | 'assertive';\n\n/**\n * `<skra-toast>` — an ephemeral, auto-dismissing feedback message rendered inside a\n * `<skra-toast-region>` top-layer stack (Feedback/Status family, ADR 0052; Tier 2 overlay,\n * ADR 0044). Visually an Alert (intent×emphasis seam, 4th consumer) with a timer.\n *\n * Announcement (ADR 0052 §7): this host carries NO `role`/`aria-live`. On appearance the\n * toast pushes its message text into the region's persistent role-only announcer via the\n * injected `SkraToastAnnouncer`, at the politeness of `live` (`off` → no announcement).\n *\n * Auto-dismiss (WCAG 2.2.1): after `duration` ms the toast emits `(dismissed)`. The timer\n * PAUSES on hover and on focus-within and resumes with the remaining time; `duration=0`\n * disables it (persistent — pair with `dismissible`). Forge does NOT self-remove — the\n * consumer removes the model from its array on `(dismissed)` (agnostic doctrine; the Alert\n * precedent). `(dismissed)` is the single removal channel (timer elapse OR close control).\n */\n@Component({\n selector: 'skra-toast',\n standalone: true,\n imports: [SkraToastIcon],\n templateUrl: './toast.html',\n styleUrl: './toast.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var])\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-emphasis]': 'emphasis()',\n // Smart Slot layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)\n '[attr.data-skra-has-icon]': 'hasIcon() ? \"\" : null',\n // NO `role` / NO `aria-live` here — the region announces (ADR 0052 §7).\n // Pause/resume the auto-dismiss timer on hover + focus (WCAG 2.2.1 Timing Adjustable).\n '(mouseenter)': 'pause()',\n '(mouseleave)': 'resume()',\n '(focusin)': 'pause()',\n '(focusout)': 'resume()',\n },\n})\nexport class SkraToast {\n // --- Variant Surface (ADR 035) ---\n readonly intent = input<ToastIntent>('neutral');\n readonly emphasis = input<ToastEmphasis>('medium');\n\n // --- Announcement (ADR 0052 §7) ---\n readonly live = input<ToastLive>('polite');\n\n // --- Auto-dismiss + dismissal ---\n readonly duration = input<number>(5000);\n readonly dismissible = input(false, { transform: booleanAttribute });\n readonly dismissed = output<void>();\n\n // --- Smart Slots v2.0 (ADR 020) ---\n readonly iconSlot = contentChild(SkraToastIcon);\n readonly hasIcon = computed(() => !!this.iconSlot());\n\n /** The message column — its text is the announcement (excludes the icon + sr-only close label). */\n private readonly contentRef =\n viewChild.required<ElementRef<HTMLElement>>('content');\n\n private readonly announcer = inject(SKRA_TOAST_ANNOUNCER, {\n optional: true,\n });\n\n private timerId: ReturnType<typeof setTimeout> | null = null;\n private remaining = 0;\n private startedAt = 0;\n\n constructor() {\n afterNextRender(() => {\n // Announce on appearance (browser-only; projected content is present post-render).\n const live = this.live();\n if (live !== 'off' && this.announcer) {\n const text = this.contentRef().nativeElement.textContent?.trim() ?? '';\n if (text) this.announcer.announce(text, live as SkraToastPoliteness);\n }\n // Start the auto-dismiss countdown (timers are browser-only — SSR-safe by construction).\n this.remaining = this.duration();\n this.start();\n });\n inject(DestroyRef).onDestroy(() => this.clear());\n }\n\n protected onDismiss(): void {\n this.clear();\n this.dismissed.emit();\n }\n\n /** Pause the countdown, banking the remaining time (WCAG 2.2.1). */\n protected pause(): void {\n if (this.timerId === null) return;\n clearTimeout(this.timerId);\n this.timerId = null;\n this.remaining -= Date.now() - this.startedAt;\n }\n\n /** Resume the countdown with the banked remaining time. */\n protected resume(): void {\n if (this.timerId !== null) return;\n this.start();\n }\n\n private start(): void {\n if (this.remaining <= 0) return; // duration=0 (or fully elapsed) → persistent\n this.startedAt = Date.now();\n this.timerId = setTimeout(() => {\n this.timerId = null;\n this.dismissed.emit();\n }, this.remaining);\n }\n\n private clear(): void {\n if (this.timerId !== null) {\n clearTimeout(this.timerId);\n this.timerId = null;\n }\n }\n}\n","@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n afterRenderEffect,\n contentChildren,\n input,\n signal,\n viewChild,\n} from '@angular/core';\nimport { SkraToast } from './toast';\nimport {\n SKRA_TOAST_ANNOUNCER,\n type SkraToastAnnouncer,\n type SkraToastPoliteness,\n} from './toast-announcer';\n\n/**\n * ToastPlacement — viewport corner, logical (RTL-correct). `block-start`/`block-end` = the\n * top/bottom edge; `inline-start`/`center`/`inline-end` = the horizontal position.\n */\nexport type ToastPlacement =\n | 'block-start inline-start'\n | 'block-start center'\n | 'block-start inline-end'\n | 'block-end inline-start'\n | 'block-end center'\n | 'block-end inline-end';\n\n/**\n * `<skra-toast-region>` — the persistent, app-root manager for `<skra-toast>` (ADR 0044 §7\n * non-anchored top-layer; ADR 0052 §7 announcer). Place ONCE near the app root; the consumer\n * projects its own `@for` of toast models into it and owns the array (agnostic doctrine —\n * a `ToastService` push/remove helper is a consumer recipe, NOT shipped here).\n *\n * Two mechanisms:\n * - Announcement (ADR 0052 §7): provides `SkraToastAnnouncer` + renders TWO persistent,\n * visually-hidden, role-only announcers (`role=\"status\"` polite / `role=\"alert\"` assertive).\n * A toast pushes its text on appearance; identical repeated messages re-announce via a\n * clear-then-set across two frames (forces a live-region mutation).\n * - Top layer (ADR 0044 §7): a SINGLE `popover=\"manual\"` stack (not `auto` — no light-dismiss /\n * Escape collapse; not N popovers). Shown when non-empty; RE-ASSERTS top-layer order on each\n * addition (`hidePopover()`+`showPopover()`) so a toast raised over an open modal `<dialog>`\n * paints above it. Paint-only — never moves focus, never disturbs the dialog. Zero z-index.\n */\n@Component({\n selector: 'skra-toast-region',\n standalone: true,\n templateUrl: './toast-region.html',\n styleUrl: './toast-region.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n '[attr.data-skra-placement]': 'placement()',\n },\n providers: [{ provide: SKRA_TOAST_ANNOUNCER, useExisting: SkraToastRegion }],\n})\nexport class SkraToastRegion implements SkraToastAnnouncer {\n readonly placement = input<ToastPlacement>('block-end inline-end');\n\n /** The two persistent role-only announcer buffers (ADR 0052 §7). */\n protected readonly politeMsg = signal('');\n protected readonly assertiveMsg = signal('');\n\n private readonly toasts = contentChildren(SkraToast);\n private readonly stackEl =\n viewChild.required<ElementRef<HTMLElement>>('stack');\n\n /** Tracked locally — jsdom/SSR have no `:popover-open`; never read it back. */\n private shown = false;\n private prevCount = 0;\n\n constructor() {\n // Browser-only (afterRender family never runs on the server — SSR-safe, O-18). Reads the\n // contentChildren signal so it re-runs whenever the visible toast set changes.\n afterRenderEffect(() => {\n // Re-assert keys on the COUNT, not toast identity: a remove+add in the SAME change-detection\n // tick keeps `n` unchanged and skips the re-assert, so the new toast would not be raised above\n // an already-open modal. Accepted for the auto-dismiss MVP (paint-only; announcement is\n // unaffected); the cross-browser top-layer pass folds into O-9 (spec Open Question 3).\n const n = this.toasts().length;\n const stack = this.stackEl().nativeElement;\n if (n > 0) {\n if (n > this.prevCount && this.shown) {\n // Re-assert top-layer order on additions (ADR 0044 §7) — drop then re-add to the top.\n stack.hidePopover?.();\n this.shown = false;\n }\n if (!this.shown) {\n stack.showPopover?.();\n this.shown = true;\n }\n } else if (this.shown) {\n stack.hidePopover?.();\n this.shown = false;\n }\n this.prevCount = n;\n });\n }\n\n /**\n * ADR 0052 §7 — write `text` into the matching persistent announcer. Clear-then-set across two\n * animation frames so a repeated IDENTICAL message still mutates the live region and re-announces\n * (the \"repeated action\" case). `off` toasts never call this.\n */\n announce(text: string, politeness: SkraToastPoliteness): void {\n const target =\n politeness === 'assertive' ? this.assertiveMsg : this.politeMsg;\n target.set('');\n requestAnimationFrame(() => requestAnimationFrame(() => target.set(text)));\n }\n}\n","<div class=\"skra-toast-stack\" popover=\"manual\" #stack>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!--\r\n ADR 0052 §7 — two PERSISTENT, role-only live announcers, held in normal flow (NOT inside the\r\n popover, so they are pre-armed and announce regardless of the stack's shown/paint state).\r\n role=\"status\" carries aria-live=polite + aria-atomic; role=\"alert\" carries assertive + atomic\r\n (implicitly — no explicit aria-live, ADR 0052 rule 2). Each holds one message at a time.\r\n-->\r\n<div class=\"skra-sr-only\" role=\"status\">{{ politeMsg() }}</div>\r\n<div class=\"skra-sr-only\" role=\"alert\">{{ assertiveMsg() }}</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":";;;AAEA;;;;;;AAMG;MAKU,aAAa,CAAA;uGAAb,aAAa,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAb,aAAa,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,QAAA,EAAA,EAAA,EAAA,CAAA;;2FAAb,aAAa,EAAA,UAAA,EAAA,CAAA;kBAJzB,SAAS;AAAC,YAAA,IAAA,EAAA,CAAA;AACT,oBAAA,QAAQ,EAAE,mBAAmB;AAC7B,oBAAA,UAAU,EAAE,IAAI;AACjB,iBAAA;;;MCcY,oBAAoB,GAAG,IAAI,cAAc,CACpD,sBAAsB;;ACWxB;;;;;;;;;;;;;;AAcG;MAuBU,SAAS,CAAA;;IAEX,MAAM,GAAG,KAAK,CAAc,SAAS;+EAAC;IACtC,QAAQ,GAAG,KAAK,CAAgB,QAAQ;iFAAC;;IAGzC,IAAI,GAAG,KAAK,CAAY,QAAQ;6EAAC;;IAGjC,QAAQ,GAAG,KAAK,CAAS,IAAI;iFAAC;IAC9B,WAAW,GAAG,KAAK,CAAC,KAAK,mFAAI,SAAS,EAAE,gBAAgB,EAAA,CAAG;IAC3D,SAAS,GAAG,MAAM,EAAQ;;IAG1B,QAAQ,GAAG,YAAY,CAAC,aAAa;iFAAC;IACtC,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,EAAE;gFAAC;;AAGnC,IAAA,UAAU,GACzB,SAAS,CAAC,QAAQ,CAA0B,SAAS;mFAAC;AAEvC,IAAA,SAAS,GAAG,MAAM,CAAC,oBAAoB,EAAE;AACxD,QAAA,QAAQ,EAAE,IAAI;AACf,KAAA,CAAC;IAEM,OAAO,GAAyC,IAAI;IACpD,SAAS,GAAG,CAAC;IACb,SAAS,GAAG,CAAC;AAErB,IAAA,WAAA,GAAA;QACE,eAAe,CAAC,MAAK;;AAEnB,YAAA,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE;YACxB,IAAI,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE;AACpC,gBAAA,MAAM,IAAI,GAAG,IAAI,CAAC,UAAU,EAAE,CAAC,aAAa,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE;AACtE,gBAAA,IAAI,IAAI;oBAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,IAA2B,CAAC;YACtE;;AAEA,YAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE;YAChC,IAAI,CAAC,KAAK,EAAE;AACd,QAAA,CAAC,CAAC;AACF,QAAA,MAAM,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IAClD;IAEU,SAAS,GAAA;QACjB,IAAI,CAAC,KAAK,EAAE;AACZ,QAAA,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;IACvB;;IAGU,KAAK,GAAA;AACb,QAAA,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI;YAAE;AAC3B,QAAA,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC;AAC1B,QAAA,IAAI,CAAC,OAAO,GAAG,IAAI;QACnB,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS;IAC/C;;IAGU,MAAM,GAAA;AACd,QAAA,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI;YAAE;QAC3B,IAAI,CAAC,KAAK,EAAE;IACd;IAEQ,KAAK,GAAA;AACX,QAAA,IAAI,IAAI,CAAC,SAAS,IAAI,CAAC;AAAE,YAAA,OAAO;AAChC,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE;AAC3B,QAAA,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,MAAK;AAC7B,YAAA,IAAI,CAAC,OAAO,GAAG,IAAI;AACnB,YAAA,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;AACvB,QAAA,CAAC,EAAE,IAAI,CAAC,SAAS,CAAC;IACpB;IAEQ,KAAK,GAAA;AACX,QAAA,IAAI,IAAI,CAAC,OAAO,KAAK,IAAI,EAAE;AACzB,YAAA,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC;AAC1B,YAAA,IAAI,CAAC,OAAO,GAAG,IAAI;QACrB;IACF;uGA7EW,SAAS,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;2FAAT,SAAS,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,YAAA,EAAA,MAAA,EAAA,EAAA,MAAA,EAAA,EAAA,iBAAA,EAAA,QAAA,EAAA,UAAA,EAAA,QAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,IAAA,EAAA,EAAA,iBAAA,EAAA,MAAA,EAAA,UAAA,EAAA,MAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,QAAA,EAAA,EAAA,iBAAA,EAAA,UAAA,EAAA,UAAA,EAAA,UAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,WAAA,EAAA,EAAA,iBAAA,EAAA,aAAA,EAAA,UAAA,EAAA,aAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,OAAA,EAAA,EAAA,SAAA,EAAA,WAAA,EAAA,EAAA,IAAA,EAAA,EAAA,SAAA,EAAA,EAAA,YAAA,EAAA,SAAA,EAAA,YAAA,EAAA,UAAA,EAAA,SAAA,EAAA,SAAA,EAAA,UAAA,EAAA,UAAA,EAAA,EAAA,UAAA,EAAA,EAAA,uBAAA,EAAA,UAAA,EAAA,yBAAA,EAAA,YAAA,EAAA,yBAAA,EAAA,yBAAA,EAAA,EAAA,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,UAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAca,aAAa,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,YAAA,EAAA,YAAA,EAAA,KAAA,EAAA,IAAA,EAAA,SAAA,EAAA,CAAA,SAAA,CAAA,EAAA,WAAA,EAAA,IAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECzFhD,wfAgBA,EAAA,MAAA,EAAA,CAAA,m+LAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FD2Da,SAAS,EAAA,UAAA,EAAA,CAAA;kBAtBrB,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,YAAY,EAAA,UAAA,EACV,IAAI,EAAA,OAAA,EACP,CAAC,aAAa,CAAC,EAAA,eAAA,EAGP,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;;AAEJ,wBAAA,yBAAyB,EAAE,UAAU;AACrC,wBAAA,2BAA2B,EAAE,YAAY;;AAEzC,wBAAA,2BAA2B,EAAE,uBAAuB;;;AAGpD,wBAAA,cAAc,EAAE,SAAS;AACzB,wBAAA,cAAc,EAAE,UAAU;AAC1B,wBAAA,WAAW,EAAE,SAAS;AACtB,wBAAA,YAAY,EAAE,UAAU;AACzB,qBAAA,EAAA,QAAA,EAAA,wfAAA,EAAA,MAAA,EAAA,CAAA,m+LAAA,CAAA,EAAA;AAgBgC,SAAA,CAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,QAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,IAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,MAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,UAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,WAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,aAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,MAAA,EAAA,IAAA,EAAA,CAAA,WAAA,CAAA,EAAA,CAAA,EAAA,QAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,YAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MAAA,aAAa,qEAKA,SAAS,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AEhEzD;;;;;;;;;;;;;;;AAeG;MAaU,eAAe,CAAA;IACjB,SAAS,GAAG,KAAK,CAAiB,sBAAsB;kFAAC;;IAG/C,SAAS,GAAG,MAAM,CAAC,EAAE;kFAAC;IACtB,YAAY,GAAG,MAAM,CAAC,EAAE;qFAAC;IAE3B,MAAM,GAAG,eAAe,CAAC,SAAS;+EAAC;AACnC,IAAA,OAAO,GACtB,SAAS,CAAC,QAAQ,CAA0B,OAAO;gFAAC;;IAG9C,KAAK,GAAG,KAAK;IACb,SAAS,GAAG,CAAC;AAErB,IAAA,WAAA,GAAA;;;QAGE,iBAAiB,CAAC,MAAK;;;;;YAKrB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM;YAC9B,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC,aAAa;AAC1C,YAAA,IAAI,CAAC,GAAG,CAAC,EAAE;gBACT,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,EAAE;;AAEpC,oBAAA,KAAK,CAAC,WAAW,IAAI;AACrB,oBAAA,IAAI,CAAC,KAAK,GAAG,KAAK;gBACpB;AACA,gBAAA,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;AACf,oBAAA,KAAK,CAAC,WAAW,IAAI;AACrB,oBAAA,IAAI,CAAC,KAAK,GAAG,IAAI;gBACnB;YACF;AAAO,iBAAA,IAAI,IAAI,CAAC,KAAK,EAAE;AACrB,gBAAA,KAAK,CAAC,WAAW,IAAI;AACrB,gBAAA,IAAI,CAAC,KAAK,GAAG,KAAK;YACpB;AACA,YAAA,IAAI,CAAC,SAAS,GAAG,CAAC;AACpB,QAAA,CAAC,CAAC;IACJ;AAEA;;;;AAIG;IACH,QAAQ,CAAC,IAAY,EAAE,UAA+B,EAAA;AACpD,QAAA,MAAM,MAAM,GACV,UAAU,KAAK,WAAW,GAAG,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC,SAAS;AACjE,QAAA,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;AACd,QAAA,qBAAqB,CAAC,MAAM,qBAAqB,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5E;uGArDW,eAAe,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA;AAAf,IAAA,OAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,QAAA,EAAA,IAAA,EAAA,eAAe,EAAA,YAAA,EAAA,IAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,EAAA,SAAA,EAAA,EAAA,iBAAA,EAAA,WAAA,EAAA,UAAA,EAAA,WAAA,EAAA,QAAA,EAAA,IAAA,EAAA,UAAA,EAAA,KAAA,EAAA,iBAAA,EAAA,IAAA,EAAA,EAAA,EAAA,IAAA,EAAA,EAAA,UAAA,EAAA,EAAA,0BAAA,EAAA,aAAA,EAAA,EAAA,EAAA,SAAA,EAFf,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC,EAAA,OAAA,EAAA,CAAA,EAAA,YAAA,EAAA,QAAA,EAAA,SAAA,EASlC,SAAS,+JCjErD,iqBAYA,EAAA,MAAA,EAAA,CAAA,ykDAAA,CAAA,EAAA,eAAA,EAAA,EAAA,CAAA,uBAAA,CAAA,MAAA,EAAA,CAAA;;2FD8Ca,eAAe,EAAA,UAAA,EAAA,CAAA;kBAZ3B,SAAS;+BACE,mBAAmB,EAAA,UAAA,EACjB,IAAI,EAAA,eAAA,EAGC,uBAAuB,CAAC,MAAM,EAAA,aAAA,EAChC,iBAAiB,CAAC,QAAQ,EAAA,IAAA,EACnC;AACJ,wBAAA,4BAA4B,EAAE,aAAa;qBAC5C,EAAA,SAAA,EACU,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,WAAW,EAAA,eAAiB,EAAE,CAAC,EAAA,QAAA,EAAA,iqBAAA,EAAA,MAAA,EAAA,CAAA,ykDAAA,CAAA,EAAA;AASlC,SAAA,CAAA,EAAA,cAAA,EAAA,MAAA,EAAA,EAAA,cAAA,EAAA,EAAA,SAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,KAAA,EAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,IAAA,EAAA,KAAA,EAAA,WAAA,EAAA,QAAA,EAAA,KAAA,EAAA,CAAA,EAAA,CAAA,EAAA,MAAA,EAAA,CAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,UAAA,CAAA,MAAA,SAAS,kEAEL,OAAO,EAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,CAAA,EAAA,EAAA,CAAA;;AEnEvD;;AAEG;;;;"}
|
|
1
|
+
{"version":3,"file":"skra-ui-toast.mjs","sources":["../../../../libs/ui/toast/src/lib/toast.directives.ts","../../../../libs/ui/toast/src/lib/toast/toast-announcer.ts","../../../../libs/ui/toast/src/lib/toast/toast.ts","../../../../libs/ui/toast/src/lib/toast/toast.html","../../../../libs/ui/toast/src/lib/toast/toast-region.ts","../../../../libs/ui/toast/src/lib/toast/toast-region.html","../../../../libs/ui/toast/src/skra-ui-toast.ts"],"sourcesContent":["import { Directive } from '@angular/core';\n\n/**\n * Marker directive for the leading icon slot of `<skra-toast>`.\n * Detected via `contentChild` (ADR 020 Smart Slots v2.0) to toggle the icon\n * wrapper without emitting an empty DOM node. Feedback-local (not the button\n * lib's `[skra-start]`) to avoid a cross-lib marker dependency — mirrors\n * `[skra-alert-icon]` / `[skra-badge-icon]`.\n */\n@Directive({\n selector: '[skra-toast-icon]',\n standalone: true,\n})\nexport class SkraToastIcon {}\n","import { InjectionToken } from '@angular/core';\n\n/**\n * Politeness routed to the toast region's role-only announcer (ADR 0052 §7).\n * `off` never reaches the announcer (no announcement), so the seam only carries\n * the two announced levels.\n */\nexport type SkraToastPoliteness = 'polite' | 'assertive';\n\n/**\n * The ADR 0052 §7 announcement seam. Provided by `<skra-toast-region>` and injected\n * (optionally) by each projected `<skra-toast>`. The toast pushes its message text on\n * appearance; the region writes it into the matching PERSISTENT, role-only announcer\n * (`role=\"status\"` for polite / `role=\"alert\"` for assertive) — never a role/`aria-live`\n * on the ephemeral toast host. This is why a live region pre-exists the content it\n * announces (WCAG 4.1.3): the announcers are rendered from the region's first render.\n *\n * Narrow seam (like `SkraSelectPanel` / `SkraFieldContext`): the toast depends on the\n * interface, not the concrete region. Content-projected toasts inject from their DECLARED\n * parent element (= the region), the same DI mechanism as `SkraFieldContext` (ADR 013).\n */\nexport interface SkraToastAnnouncer {\n /** Announce `text` at the given politeness by writing it into the matching live region. */\n announce(text: string, politeness: SkraToastPoliteness): void;\n}\n\nexport const SKRA_TOAST_ANNOUNCER = new InjectionToken<SkraToastAnnouncer>(\n 'SKRA_TOAST_ANNOUNCER',\n);\n","import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n ViewEncapsulation,\n afterNextRender,\n booleanAttribute,\n computed,\n contentChild,\n inject,\n input,\n output,\n viewChild,\n} from '@angular/core';\nimport { SkraToastIcon } from '../toast.directives';\nimport {\n SKRA_TOAST_ANNOUNCER,\n type SkraToastPoliteness,\n} from './toast-announcer';\n\n/**\n * ToastIntent — semantic feedback meaning (ADR 035 §3.1, downward subset). Excludes the\n * action intents `primary`/`secondary`. Same enum as Alert/Badge.\n */\nexport type ToastIntent = 'neutral' | 'info' | 'success' | 'warning' | 'danger';\n\n/** ToastEmphasis — `high` = filled, `medium` = soft. `low` deferred (ADR 035 §3.1). */\nexport type ToastEmphasis = 'high' | 'medium';\n\n/**\n * ToastLive — screen-reader announcement politeness (ADR 0052). For Toast the politeness\n * is routed to the REGION's announcer (ADR 0052 §7); it does NOT set a role on this host.\n * Default `polite` (toasts are always dynamically presented — ADR 0052 §4). `assertive`\n * for error toasts, set explicitly by the consumer — NEVER auto-derived from `intent`.\n */\nexport type ToastLive = 'off' | 'polite' | 'assertive';\n\n/**\n * `<skra-toast>` — an ephemeral, auto-dismissing feedback message rendered inside a\n * `<skra-toast-region>` top-layer stack (Feedback/Status family, ADR 0052; Tier 2 overlay,\n * ADR 0044). Visually an Alert (intent×emphasis seam, 4th consumer) with a timer.\n *\n * Announcement (ADR 0052 §7): this host carries NO `role`/`aria-live`. On appearance the\n * toast pushes its message text into the region's persistent role-only announcer via the\n * injected `SkraToastAnnouncer`, at the politeness of `live` (`off` → no announcement).\n *\n * Auto-dismiss (WCAG 2.2.1): after `duration` ms the toast emits `(dismissed)`. The timer\n * PAUSES on hover and on focus-within and resumes with the remaining time; `duration=0`\n * disables it (persistent — pair with `dismissible`). Forge does NOT self-remove — the\n * consumer removes the model from its array on `(dismissed)` (agnostic doctrine; the Alert\n * precedent). `(dismissed)` is the single removal channel (timer elapse OR close control).\n */\n@Component({\n selector: 'skra-toast',\n standalone: true,\n imports: [SkraToastIcon],\n templateUrl: './toast.html',\n styleUrl: './toast.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n // Variant Surface reflection (ADR 035 §3.5; ADR 021 — never [style.--var])\n '[attr.data-skra-intent]': 'intent()',\n '[attr.data-skra-emphasis]': 'emphasis()',\n // Smart Slot layout reflection (ADR 020 v2.0 — slot-presence, State-Surface-exempt §3.6)\n '[attr.data-skra-has-icon]': 'hasIcon() ? \"\" : null',\n // NO `role` / NO `aria-live` here — the region announces (ADR 0052 §7).\n // Pause/resume the auto-dismiss timer on hover + focus (WCAG 2.2.1 Timing Adjustable).\n '(mouseenter)': 'pause()',\n '(mouseleave)': 'resume()',\n '(focusin)': 'pause()',\n '(focusout)': 'resume()',\n },\n})\nexport class SkraToast {\n // --- Variant Surface (ADR 035) ---\n readonly intent = input<ToastIntent>('neutral');\n readonly emphasis = input<ToastEmphasis>('medium');\n\n // --- Announcement (ADR 0052 §7) ---\n readonly live = input<ToastLive>('polite');\n\n // --- Auto-dismiss + dismissal ---\n readonly duration = input<number>(5000);\n readonly dismissible = input(false, { transform: booleanAttribute });\n readonly dismissed = output<void>();\n\n // --- Smart Slots v2.0 (ADR 020) ---\n readonly iconSlot = contentChild(SkraToastIcon);\n readonly hasIcon = computed(() => !!this.iconSlot());\n\n /** The message column — its text is the announcement (excludes the icon + sr-only close label). */\n private readonly contentRef =\n viewChild.required<ElementRef<HTMLElement>>('content');\n\n private readonly announcer = inject(SKRA_TOAST_ANNOUNCER, {\n optional: true,\n });\n\n private timerId: ReturnType<typeof setTimeout> | null = null;\n private remaining = 0;\n private startedAt = 0;\n\n constructor() {\n afterNextRender(() => {\n // Announce on appearance (browser-only; projected content is present post-render).\n const live = this.live();\n if (live !== 'off' && this.announcer) {\n const text = this.contentRef().nativeElement.textContent?.trim() ?? '';\n if (text) this.announcer.announce(text, live as SkraToastPoliteness);\n }\n // Start the auto-dismiss countdown (timers are browser-only — SSR-safe by construction).\n this.remaining = this.duration();\n this.start();\n });\n inject(DestroyRef).onDestroy(() => this.clear());\n }\n\n protected onDismiss(): void {\n this.clear();\n this.dismissed.emit();\n }\n\n /** Pause the countdown, banking the remaining time (WCAG 2.2.1). */\n protected pause(): void {\n if (this.timerId === null) return;\n clearTimeout(this.timerId);\n this.timerId = null;\n this.remaining -= Date.now() - this.startedAt;\n }\n\n /** Resume the countdown with the banked remaining time. */\n protected resume(): void {\n if (this.timerId !== null) return;\n this.start();\n }\n\n private start(): void {\n if (this.remaining <= 0) return; // duration=0 (or fully elapsed) → persistent\n this.startedAt = Date.now();\n this.timerId = setTimeout(() => {\n this.timerId = null;\n this.dismissed.emit();\n }, this.remaining);\n }\n\n private clear(): void {\n if (this.timerId !== null) {\n clearTimeout(this.timerId);\n this.timerId = null;\n }\n }\n}\n","@if (hasIcon()) {\r\n<span class=\"skra-toast-icon\">\r\n <ng-content select=\"[skra-toast-icon]\"></ng-content>\r\n</span>\r\n}\r\n\r\n<div class=\"skra-toast-content\" #content>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n@if (dismissible()) {\r\n<button type=\"button\" class=\"skra-toast-dismiss\" (click)=\"onDismiss()\">\r\n <span class=\"skra-toast-dismiss-glyph\" aria-hidden=\"true\">×</span>\r\n <ng-content select=\"[skra-toast-close-label]\"></ng-content>\r\n</button>\r\n}\r\n","import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n ViewEncapsulation,\n afterRenderEffect,\n contentChildren,\n input,\n signal,\n viewChild,\n} from '@angular/core';\nimport { SkraToast } from './toast';\nimport {\n SKRA_TOAST_ANNOUNCER,\n type SkraToastAnnouncer,\n type SkraToastPoliteness,\n} from './toast-announcer';\n\n/**\n * ToastPlacement — viewport corner, logical (RTL-correct). `block-start`/`block-end` = the\n * top/bottom edge; `inline-start`/`center`/`inline-end` = the horizontal position.\n */\nexport type ToastPlacement =\n | 'block-start inline-start'\n | 'block-start center'\n | 'block-start inline-end'\n | 'block-end inline-start'\n | 'block-end center'\n | 'block-end inline-end';\n\n/**\n * `<skra-toast-region>` — the persistent, app-root manager for `<skra-toast>` (ADR 0044 §7\n * non-anchored top-layer; ADR 0052 §7 announcer). Place ONCE near the app root; the consumer\n * projects its own `@for` of toast models into it and owns the array (agnostic doctrine —\n * a `ToastService` push/remove helper is a consumer recipe, NOT shipped here).\n *\n * Two mechanisms:\n * - Announcement (ADR 0052 §7): provides `SkraToastAnnouncer` + renders TWO persistent,\n * visually-hidden, role-only announcers (`role=\"status\"` polite / `role=\"alert\"` assertive).\n * A toast pushes its text on appearance; identical repeated messages re-announce via a\n * clear-then-set across two frames (forces a live-region mutation).\n * - Top layer (ADR 0044 §7): a SINGLE `popover=\"manual\"` stack (not `auto` — no light-dismiss /\n * Escape collapse; not N popovers). Shown when non-empty; RE-ASSERTS top-layer order on each\n * addition (`hidePopover()`+`showPopover()`) so a toast raised over an open modal `<dialog>`\n * paints above it. Paint-only — never moves focus, never disturbs the dialog. Zero z-index.\n */\n@Component({\n selector: 'skra-toast-region',\n standalone: true,\n templateUrl: './toast-region.html',\n styleUrl: './toast-region.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n encapsulation: ViewEncapsulation.Emulated,\n host: {\n '[attr.data-skra-placement]': 'placement()',\n },\n providers: [{ provide: SKRA_TOAST_ANNOUNCER, useExisting: SkraToastRegion }],\n})\nexport class SkraToastRegion implements SkraToastAnnouncer {\n readonly placement = input<ToastPlacement>('block-end inline-end');\n\n /** The two persistent role-only announcer buffers (ADR 0052 §7). */\n protected readonly politeMsg = signal('');\n protected readonly assertiveMsg = signal('');\n\n private readonly toasts = contentChildren(SkraToast);\n private readonly stackEl =\n viewChild.required<ElementRef<HTMLElement>>('stack');\n\n /** Tracked locally — jsdom/SSR have no `:popover-open`; never read it back. */\n private shown = false;\n private prevCount = 0;\n\n constructor() {\n // Browser-only (afterRender family never runs on the server — SSR-safe, O-18). Reads the\n // contentChildren signal so it re-runs whenever the visible toast set changes.\n afterRenderEffect(() => {\n // Re-assert keys on the COUNT, not toast identity: a remove+add in the SAME change-detection\n // tick keeps `n` unchanged and skips the re-assert, so the new toast would not be raised above\n // an already-open modal. Accepted for the auto-dismiss MVP (paint-only; announcement is\n // unaffected); the cross-browser top-layer pass folds into O-9 (spec Open Question 3).\n const n = this.toasts().length;\n const stack = this.stackEl().nativeElement;\n if (n > 0) {\n if (n > this.prevCount && this.shown) {\n // Re-assert top-layer order on additions (ADR 0044 §7) — drop then re-add to the top.\n stack.hidePopover?.();\n this.shown = false;\n }\n if (!this.shown) {\n stack.showPopover?.();\n this.shown = true;\n }\n } else if (this.shown) {\n stack.hidePopover?.();\n this.shown = false;\n }\n this.prevCount = n;\n });\n }\n\n /**\n * ADR 0052 §7 — write `text` into the matching persistent announcer. Clear-then-set across two\n * animation frames so a repeated IDENTICAL message still mutates the live region and re-announces\n * (the \"repeated action\" case). `off` toasts never call this.\n */\n announce(text: string, politeness: SkraToastPoliteness): void {\n const target =\n politeness === 'assertive' ? this.assertiveMsg : this.politeMsg;\n target.set('');\n requestAnimationFrame(() => requestAnimationFrame(() => target.set(text)));\n }\n}\n","<div class=\"skra-toast-stack\" popover=\"manual\" #stack>\r\n <ng-content></ng-content>\r\n</div>\r\n\r\n<!--\r\n ADR 0052 §7 — two PERSISTENT, role-only live announcers, held in normal flow (NOT inside the\r\n popover, so they are pre-armed and announce regardless of the stack's shown/paint state).\r\n role=\"status\" carries aria-live=polite + aria-atomic; role=\"alert\" carries assertive + atomic\r\n (implicitly — no explicit aria-live, ADR 0052 rule 2). Each holds one message at a time.\r\n-->\r\n<div class=\"skra-sr-only\" role=\"status\">{{ politeMsg() }}</div>\r\n<div class=\"skra-sr-only\" role=\"alert\">{{ assertiveMsg() }}</div>\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skra/ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.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.
|
|
13
|
+
"@skra/tokens": "^0.8.0"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@floating-ui/dom": "^1.7.6",
|
|
@@ -78,6 +78,10 @@
|
|
|
78
78
|
"types": "./types/skra-ui-field.d.ts",
|
|
79
79
|
"default": "./fesm2022/skra-ui-field.mjs"
|
|
80
80
|
},
|
|
81
|
+
"./file-upload": {
|
|
82
|
+
"types": "./types/skra-ui-file-upload.d.ts",
|
|
83
|
+
"default": "./fesm2022/skra-ui-file-upload.mjs"
|
|
84
|
+
},
|
|
81
85
|
"./icon": {
|
|
82
86
|
"types": "./types/skra-ui-icon.d.ts",
|
|
83
87
|
"default": "./fesm2022/skra-ui-icon.mjs"
|
package/types/skra-ui-alert.d.ts
CHANGED
|
@@ -22,6 +22,37 @@ declare class SkraAlertTitle {
|
|
|
22
22
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkraAlertTitle, never>;
|
|
23
23
|
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SkraAlertTitle, "[skra-alert-title]", never, {}, {}, never, never, true, never>;
|
|
24
24
|
}
|
|
25
|
+
/**
|
|
26
|
+
* Marker directive for an ACTION of `<skra-alert>` — "what to do next" ("Try again").
|
|
27
|
+
* Put it on each action; several are allowed and keep the consumer's order. Detected via
|
|
28
|
+
* `contentChildren` (ADR 020) to render the actions region below the message only when one
|
|
29
|
+
* exists. The region sits inside the content column, so it never collides with the dismiss
|
|
30
|
+
* control.
|
|
31
|
+
*
|
|
32
|
+
* The action keeps its OWN meaning: the alert never sets or changes a projected button's
|
|
33
|
+
* `intent` / `emphasis` (ADR 0059 R59.1) — a retry inside a danger alert is not a destructive
|
|
34
|
+
* action. What the alert owns is the region's layout and the focus ring its actions draw on the
|
|
35
|
+
* alert's fill (R59.3). Guaranteed legible on the alert's fill (ADR 0059 R59.2 — the gate
|
|
36
|
+
* measures exactly these):
|
|
37
|
+
*
|
|
38
|
+
* | Alert emphasis | Guaranteed actions |
|
|
39
|
+
* | ------------------- | --------------------------------------------------------------- |
|
|
40
|
+
* | `medium` (default) | `neutral` at any emphasis; any intent at `emphasis="high"` |
|
|
41
|
+
* | `high` | any intent at `emphasis="high"` other than the alert's intent |
|
|
42
|
+
*
|
|
43
|
+
* Anything else (a coloured `medium`/`low` action, a `medium`/`low` action on a `high` alert,
|
|
44
|
+
* a `high` action in the alert's own intent) is unsupported. The zero-config
|
|
45
|
+
* `<button skraButton skra-alert-actions>` (`neutral × high`) is guaranteed everywhere except
|
|
46
|
+
* on a `neutral × high` alert. Admitted atom: `button[skraButton]`.
|
|
47
|
+
*
|
|
48
|
+
* Announcement: a live alert (`live="polite"|"assertive"`) announces its whole text, action
|
|
49
|
+
* labels included (the implicit `role` carries `aria-atomic`, ADR 0052) — the label tells the
|
|
50
|
+
* user an action exists.
|
|
51
|
+
*/
|
|
52
|
+
declare class SkraAlertActions {
|
|
53
|
+
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkraAlertActions, never>;
|
|
54
|
+
static ɵdir: _angular_core.ɵɵDirectiveDeclaration<SkraAlertActions, "[skra-alert-actions]", never, {}, {}, never, never, true, never>;
|
|
55
|
+
}
|
|
25
56
|
|
|
26
57
|
/**
|
|
27
58
|
* AlertIntent — semantic feedback meaning (ADR 035 §3.1, downward subset).
|
|
@@ -55,6 +86,10 @@ type AlertLive = 'off' | 'polite' | 'assertive';
|
|
|
55
86
|
* Forge does NOT remove itself from the DOM — the consumer owns removal via `@if`
|
|
56
87
|
* (agnostic-atom doctrine). The close control's accessible name comes from a projected
|
|
57
88
|
* `[skra-alert-close-label]` (sr-only; ADR 033 Path 2) — the "×" glyph is `aria-hidden`.
|
|
89
|
+
*
|
|
90
|
+
* Actions (GitHub #4, ADR 0059): mark each next-step button `[skra-alert-actions]`; they render
|
|
91
|
+
* in a region below the message. The alert owns that region's layout and its focus ring, never
|
|
92
|
+
* the actions' meaning — see `SkraAlertActions` for the guaranteed combinations.
|
|
58
93
|
*/
|
|
59
94
|
declare class SkraAlert {
|
|
60
95
|
readonly intent: _angular_core.InputSignal<AlertIntent>;
|
|
@@ -66,6 +101,8 @@ declare class SkraAlert {
|
|
|
66
101
|
readonly hasIcon: _angular_core.Signal<boolean>;
|
|
67
102
|
readonly titleSlot: _angular_core.Signal<SkraAlertTitle | undefined>;
|
|
68
103
|
readonly hasTitle: _angular_core.Signal<boolean>;
|
|
104
|
+
readonly actionSlots: _angular_core.Signal<readonly SkraAlertActions[]>;
|
|
105
|
+
readonly hasActions: _angular_core.Signal<boolean>;
|
|
69
106
|
/**
|
|
70
107
|
* Map `live` politeness to the implicit-live ARIA role (ADR 0052). The role
|
|
71
108
|
* carries `aria-live` + `aria-atomic` implicitly; `off` → no live region.
|
|
@@ -73,9 +110,9 @@ declare class SkraAlert {
|
|
|
73
110
|
readonly liveRole: _angular_core.Signal<"alert" | "status" | null>;
|
|
74
111
|
protected onDismiss(): void;
|
|
75
112
|
static ɵfac: _angular_core.ɵɵFactoryDeclaration<SkraAlert, never>;
|
|
76
|
-
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraAlert, "skra-alert", never, { "intent": { "alias": "intent"; "required": false; "isSignal": true; }; "emphasis": { "alias": "emphasis"; "required": false; "isSignal": true; }; "live": { "alias": "live"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; }, { "dismissed": "dismissed"; }, ["iconSlot", "titleSlot"], ["[skra-alert-icon]", "[skra-alert-title]", "*", "[skra-alert-close-label]"], true, never>;
|
|
113
|
+
static ɵcmp: _angular_core.ɵɵComponentDeclaration<SkraAlert, "skra-alert", never, { "intent": { "alias": "intent"; "required": false; "isSignal": true; }; "emphasis": { "alias": "emphasis"; "required": false; "isSignal": true; }; "live": { "alias": "live"; "required": false; "isSignal": true; }; "dismissible": { "alias": "dismissible"; "required": false; "isSignal": true; }; }, { "dismissed": "dismissed"; }, ["iconSlot", "titleSlot", "actionSlots"], ["[skra-alert-icon]", "[skra-alert-title]", "*", "[skra-alert-actions]", "[skra-alert-close-label]"], true, never>;
|
|
77
114
|
}
|
|
78
115
|
|
|
79
|
-
export { SkraAlert, SkraAlertIcon, SkraAlertTitle };
|
|
116
|
+
export { SkraAlert, SkraAlertActions, SkraAlertIcon, SkraAlertTitle };
|
|
80
117
|
export type { AlertEmphasis, AlertIntent, AlertLive };
|
|
81
118
|
//# sourceMappingURL=skra-ui-alert.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skra-ui-alert.d.ts","sources":["../../../../libs/ui/alert/src/lib/alert.directives.ts","../../../../libs/ui/alert/src/lib/alert/alert.ts"],"mappings":";;AAEA;;;;;AAKG;AACH,cAIa,aAAa;oDAAb,aAAa;sDAAb,aAAa;AAAG;AAE7B;;;;;;;AAOG;AACH,cAIa,cAAc;oDAAd,cAAc;sDAAd,cAAc;AAAG;;
|
|
1
|
+
{"version":3,"file":"skra-ui-alert.d.ts","sources":["../../../../libs/ui/alert/src/lib/alert.directives.ts","../../../../libs/ui/alert/src/lib/alert/alert.ts"],"mappings":";;AAEA;;;;;AAKG;AACH,cAIa,aAAa;oDAAb,aAAa;sDAAb,aAAa;AAAG;AAE7B;;;;;;;AAOG;AACH,cAIa,cAAc;oDAAd,cAAc;sDAAd,cAAc;AAAG;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;AA0BG;AACH,cAIa,gBAAgB;oDAAhB,gBAAgB;sDAAhB,gBAAgB;AAAG;;AC1ChC;;;;AAIG;AACG,KAAM,WAAW;AAEvB;;;AAGG;KACS,aAAa;AAEzB;;;;AAIG;AACG,KAAM,SAAS;AAErB;;;;;;;;;;;;;;;;;;;AAmBG;AACH,cAsBa,SAAS;qBAEL,aAAA,CAAA,WAAA,CAAA,WAAA;uBACE,aAAA,CAAA,WAAA,CAAA,aAAA;mBAGJ,aAAA,CAAA,WAAA,CAAA,SAAA;0BAGO,aAAA,CAAA,wBAAA;wBACF,aAAA,CAAA,gBAAA;uBAGD,aAAA,CAAA,MAAA,CAAA,aAAA;sBACD,aAAA,CAAA,MAAA;wBAEE,aAAA,CAAA,MAAA,CAAA,cAAA;uBACD,aAAA,CAAA,MAAA;0BAIG,aAAA,CAAA,MAAA,UAAA,gBAAA;yBACD,aAAA,CAAA,MAAA;AAEnB;;;AAGG;uBACc,aAAA,CAAA,MAAA;;oDA5BN,SAAS;sDAAT,SAAS;AA0CrB;;;;","names":[]}
|