@lifecorner/angular-ui-kit 3.34.0 → 3.36.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/README.md +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-alert.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-alert.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs +6 -6
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs +82 -16
- package/fesm2022/lifecorner-angular-ui-kit-card.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs +23 -4
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs +43 -5
- package/fesm2022/lifecorner-angular-ui-kit-description-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs +30 -2
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs +45 -8
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-hero.mjs +57 -5
- package/fesm2022/lifecorner-angular-ui-kit-hero.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-internal-overlay.mjs +6 -1
- package/fesm2022/lifecorner-angular-ui-kit-internal-overlay.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs +24 -5
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-modal.mjs +2 -4
- package/fesm2022/lifecorner-angular-ui-kit-modal.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs +41 -1
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-stacked-bar-chart.mjs +47 -5
- package/fesm2022/lifecorner-angular-ui-kit-stacked-bar-chart.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-state-strip.mjs +203 -0
- package/fesm2022/lifecorner-angular-ui-kit-state-strip.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +25 -4
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs +3 -0
- package/fesm2022/lifecorner-angular-ui-kit-textarea.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit.mjs +1 -0
- package/package.json +5 -1
- package/src/styles/theme-contrast.spec.ts +74 -0
- package/types/lifecorner-angular-ui-kit-alert.d.ts +12 -2
- package/types/lifecorner-angular-ui-kit-bottom-nav.d.ts +5 -1
- package/types/lifecorner-angular-ui-kit-button.d.ts +7 -3
- package/types/lifecorner-angular-ui-kit-card.d.ts +51 -3
- package/types/lifecorner-angular-ui-kit-combobox.d.ts +36 -0
- package/types/lifecorner-angular-ui-kit-description-list.d.ts +40 -0
- package/types/lifecorner-angular-ui-kit-drawer.d.ts +37 -1
- package/types/lifecorner-angular-ui-kit-gallery.d.ts +3 -1
- package/types/lifecorner-angular-ui-kit-header.d.ts +44 -2
- package/types/lifecorner-angular-ui-kit-hero.d.ts +32 -0
- package/types/lifecorner-angular-ui-kit-internal-overlay.d.ts +9 -1
- package/types/lifecorner-angular-ui-kit-list.d.ts +17 -0
- package/types/lifecorner-angular-ui-kit-sidenav.d.ts +42 -1
- package/types/lifecorner-angular-ui-kit-stacked-bar-chart.d.ts +36 -0
- package/types/lifecorner-angular-ui-kit-state-strip.d.ts +107 -0
- package/types/lifecorner-angular-ui-kit-table.d.ts +37 -0
- package/types/lifecorner-angular-ui-kit-textarea.d.ts +17 -0
- package/types/lifecorner-angular-ui-kit-toast.d.ts +4 -2
- package/types/lifecorner-angular-ui-kit.d.ts +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-toast.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/toast/toast.service.ts","../../../../libs/angular-ui-kit/src/lib/toast/toast.component.ts","../../../../libs/angular-ui-kit/src/lib/toast/toast.component.html","../../../../libs/angular-ui-kit/src/lib/toast/toast-outlet.component.ts","../../../../libs/angular-ui-kit/src/lib/toast/toast-outlet.component.html"],"sourcesContent":["import { Injectable, PLATFORM_ID, inject, signal, Signal } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nexport type ToastVariant = 'success' | 'error' | 'warning' | 'info';\nexport type ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n\nexport interface ToastAction {\n label: string;\n onClick: () => void;\n}\n\nexport interface ToastConfig {\n message: string;\n variant?: ToastVariant;\n position?: ToastPosition;\n duration?: number;\n showCloseButton?: boolean;\n action?: ToastAction;\n}\n\nexport interface Toast extends Required<Omit<ToastConfig, 'action'>> {\n id: string;\n action?: ToastAction;\n}\n\n/**\n * Toast service for showing ephemeral notifications.\n *\n * The toasts are rendered by `<lc-toast-outlet />`, which the application\n * places once (e.g. in its shell); without it nothing is shown. The options,\n * their defaults, the timing and how a toast is announced to screen readers\n * are documented under *Feedback/Toast Outlet* (3.17).\n *\n * @example\n * ```typescript\n * private readonly toastService = inject(ToastService);\n *\n * showSuccess() {\n * this.toastService.show({\n * message: 'Changes saved successfully!',\n * variant: 'success',\n * duration: 3000\n * });\n * }\n * ```\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ToastService {\n /**\n * Public readonly signal for toasts\n */\n public readonly toasts: Signal<readonly Toast[]>;\n\n /**\n * Internal signal for toast list\n */\n private readonly toastList = signal<Toast[]>([]);\n\n private readonly MAX_TOASTS = 5;\n private toastIdCounter = 0;\n private activeTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n /** Auto-dismiss timers only make sense in the browser (and `window` does not exist on the server). */\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n constructor() {\n this.toasts = this.toastList.asReadonly();\n }\n\n /**\n * Show a toast notification\n */\n show(config: ToastConfig): string {\n const toast: Toast = {\n id: this.generateId(),\n message: config.message,\n variant: config.variant || 'info',\n position: config.position || 'top-right',\n duration: config.duration !== undefined ? config.duration : 3000,\n showCloseButton: config.showCloseButton !== undefined ? config.showCloseButton : true,\n action: config.action,\n };\n\n // Add toast to list\n let currentToasts = this.toastList();\n\n // Remove oldest toast if at max capacity\n if (currentToasts.length >= this.MAX_TOASTS) {\n const oldestToast = currentToasts[0];\n if (oldestToast) {\n this.clearTimeout(oldestToast.id);\n currentToasts = currentToasts.slice(1);\n }\n }\n\n this.toastList.set([...currentToasts, toast]);\n\n // Auto-dismiss if duration > 0\n if (toast.duration > 0 && this.isBrowser) {\n const timeoutId = setTimeout(() => {\n this.close(toast.id);\n }, toast.duration);\n\n this.activeTimeouts.set(toast.id, timeoutId);\n }\n\n return toast.id;\n }\n\n /**\n * Close a specific toast\n */\n close(id: string): void {\n this.removeToast(id);\n }\n\n /**\n * Close all toasts\n */\n closeAll(): void {\n const currentToasts = this.toastList();\n currentToasts.forEach((toast) => {\n this.clearTimeout(toast.id);\n });\n this.toastList.set([]);\n }\n\n /**\n * Generate unique toast ID\n */\n private generateId(): string {\n return `toast-${++this.toastIdCounter}-${Date.now()}`;\n }\n\n /**\n * Remove a toast from the list\n */\n private removeToast(id: string): void {\n this.clearTimeout(id);\n const currentToasts = this.toastList();\n this.toastList.set(currentToasts.filter((t) => t.id !== id));\n }\n\n /**\n * Clear timeout for a toast\n */\n private clearTimeout(id: string): void {\n const timeoutId = this.activeTimeouts.get(id);\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n this.activeTimeouts.delete(id);\n }\n }\n}\n","import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n computed,\n ViewEncapsulation,\n} from '@angular/core';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport {\n ICON_CHECK_CIRCLE,\n ICON_CIRCLE_X,\n ICON_EXCLAMATION_TRIANGLE,\n ICON_INFORMATION_CIRCLE,\n ICON_X_MARK,\n} from '@lifecorner/angular-ui-kit/icons';\nimport type { Toast, ToastVariant } from './toast.service';\n\n/**\n * Toast component for displaying ephemeral notification messages.\n *\n * Features:\n * - Semantic variants (success, warning, error, info)\n * - Auto-dismiss with configurable duration\n * - Manual dismiss with close button\n * - Icon display per variant\n * - Stacked toast positioning via ToastService + `<lc-toast-outlet />`\n * - Animated enter/exit transitions\n *\n * Usually rendered by `<lc-toast-outlet />`; can also be placed directly:\n *\n * @example\n * ```html\n * <lc-toast [toast]=\"toast\" (closed)=\"dismiss($event)\" />\n * ```\n */\n@Component({\n selector: 'lc-toast',\n standalone: true,\n imports: [IconComponent],\n viewProviders: [\n ɵprovideKitIcons([ICON_X_MARK, ICON_CHECK_CIRCLE, ICON_CIRCLE_X, ICON_EXCLAMATION_TRIANGLE, ICON_INFORMATION_CIRCLE]),\n ],\n templateUrl: './toast.component.html',\n styleUrls: ['./toast.component.scss'],\n encapsulation: ViewEncapsulation.None, // Required for dynamic variant class styling\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n '[attr.role]': 'ariaRole()',\n '[attr.aria-live]': 'ariaLive()',\n '[attr.aria-atomic]': 'announce() ? \"true\" : null',\n },\n})\nexport class ToastComponent {\n /**\n * Toast data\n */\n toast = input.required<Toast>();\n\n /**\n * Whether the toast is its own live region (`role=\"status\"`/`\"alert\"` on the\n * host). `lc-toast-outlet` sets this to false because its persistent live\n * regions already announce the toast — announcing twice would be noise.\n * @default true\n */\n announce = input<boolean>(true);\n\n /** Accessible name of the close button (`toast.showCloseButton`). */\n closeAriaLabel = input('Close notification');\n\n /**\n * Emitted when toast is closed\n */\n readonly closed = output<string>();\n\n /**\n * Computed host classes\n */\n protected hostClasses = computed(() => {\n const toast = this.toast();\n return `lc-toast lc-toast--${toast.variant}`;\n });\n\n /**\n * Computed container classes\n */\n protected containerClasses = computed(() => {\n return 'lc-toast__container';\n });\n\n /**\n * Computed ARIA role\n */\n protected ariaRole = computed(() => {\n if (!this.announce()) return null;\n const variant = this.toast().variant;\n return variant === 'error' || variant === 'warning' ? 'alert' : 'status';\n });\n\n /**\n * Computed ARIA live region priority\n */\n protected ariaLive = computed(() => {\n if (!this.announce()) return null;\n const variant = this.toast().variant;\n return variant === 'error' || variant === 'warning' ? 'assertive' : 'polite';\n });\n\n /**\n * Computed default icon based on variant\n */\n protected defaultIcon = computed(() => {\n const icons: Record<ToastVariant, string> = {\n success: 'check-circle',\n error: 'x-circle',\n warning: 'exclamation-triangle',\n info: 'information-circle',\n };\n return icons[this.toast().variant];\n });\n\n /**\n * Handle close button click\n */\n protected onCloseClick(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n this.closed.emit(this.toast().id);\n }\n\n /**\n * Handle action button click\n */\n protected onActionClick(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n const action = this.toast().action;\n if (action) {\n action.onClick();\n this.closed.emit(this.toast().id);\n }\n }\n}\n","<div [class]=\"containerClasses()\">\n <div class=\"lc-toast__icon\">\n <lc-icon [name]=\"defaultIcon()\" size=\"md\" [decorative]=\"true\" />\n </div>\n \n <div class=\"lc-toast__message\">\n {{ toast().message }}\n </div>\n \n @if (toast().action) {\n <button\n type=\"button\"\n class=\"lc-toast__action\"\n (click)=\"onActionClick($event)\"\n >\n {{ toast().action?.label }}\n </button>\n }\n \n @if (toast().showCloseButton) {\n <button\n type=\"button\"\n class=\"lc-toast__close\"\n [attr.aria-label]=\"closeAriaLabel()\"\n (click)=\"onCloseClick($event)\"\n >\n <lc-icon name=\"x-mark\" size=\"sm\" [decorative]=\"true\" />\n </button>\n }\n</div>\n","import { Component, ChangeDetectionStrategy, computed, inject, input } from '@angular/core';\nimport { OverlayInsetsService } from '@lifecorner/angular-ui-kit/internal/overlay';\nimport { ToastComponent } from './toast.component';\nimport { ToastService, type Toast, type ToastPosition } from './toast.service';\n\n/** Politeness of the live region a toast is announced from. */\ntype ToastLive = 'polite' | 'assertive';\n\nconst POSITIONS: readonly ToastPosition[] = [\n 'top-left',\n 'top-center',\n 'top-right',\n 'bottom-left',\n 'bottom-center',\n 'bottom-right',\n];\n\n/**\n * Renders the toasts of {@link ToastService}. Place it once in the application\n * shell; without it `ToastService.show()` has no visible effect.\n *\n * ```html\n * <lc-toast-outlet />\n * ```\n *\n * Toasts are stacked per `position`. Every position owns two live regions that\n * exist from the start — screen readers only announce content that is inserted\n * into an *existing* live region — one `polite` for success/info toasts and one\n * `assertive` for error/warning toasts. Dismissing a toast (close button,\n * action, auto-dismiss) removes it from the service.\n *\n * Offsets (3.28, AS-34): with `lc-app-shell` in the app (the outlet may sit\n * before or after it), the `top-*` stacks start below the shell's header and\n * the `bottom-*` stacks end above its bottom bar, each with the stack's 16 px\n * padding as the gap. The shell measures both in the browser (the header's\n * bottom edge with the top inset; the shown bar's top edge, from the\n * viewport's bottom, with the bottom inset). From 1024 px, where the bar is\n * hidden, the bottom offset is the safe-area inset. Without a shell, and in\n * prerendered HTML, both are `0px`, as before. Every stack is at most as high\n * as the space between the offsets and scrolls when its toasts need more\n * (200 % text), so each toast stays reachable.\n *\n * Bottom stacks show the newest toast nearest the edge (3.33); top stacks the\n * oldest at the top. The toasts of a stack are 8 px (`--spacing-2`) apart\n * (3.33.1), within a live region and across the two; an empty region and the\n * last toast add no space, and the stack keeps its 16 px padding. A `top-*`\n * stack lies over the page on purpose (a toast stays visible wherever the\n * page is scrolled), so in the shell it can cover a title right under the\n * header (at 360 px a toast at y 72 over an h1 at y 80): prefer `bottom-*`\n * there.\n *\n * CSS hooks (set them on `lc-toast-outlet` or any ancestor, e.g. `:root`;\n * each wins over the shell's value; write lengths, `0px` rather than `0`):\n * - `--lc-toast-outlet-offset-top` — the space kept free above the `top-*`\n * stacks. Default `0px`; with `lc-app-shell`: its header's bottom edge, or\n * `env(safe-area-inset-top, 0px)` without a header.\n * - `--lc-toast-outlet-offset-bottom` — the space kept free below the\n * `bottom-*` stacks. Default `0px`; with `lc-app-shell`: the shown bottom\n * bar's top edge, measured from the viewport's bottom, or\n * `env(safe-area-inset-bottom, 0px)` when no bar shows.\n */\n@Component({\n selector: 'lc-toast-outlet',\n standalone: true,\n imports: [ToastComponent],\n templateUrl: './toast-outlet.component.html',\n styleUrls: ['./toast-outlet.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n // The shell's measured offsets (AS-34), private; `null` without a shell,\n // so the host gets no style attribute. The public hooks win in the CSS.\n '[style.--_lc-toast-outlet-frame-top]': 'insets.top()',\n '[style.--_lc-toast-outlet-frame-bottom]': 'insets.bottom()',\n },\n})\nexport class ToastOutletComponent {\n protected readonly positions = POSITIONS;\n protected readonly liveLevels: readonly ToastLive[] = ['assertive', 'polite'];\n\n private readonly toastService = inject(ToastService);\n protected readonly insets = inject(OverlayInsetsService);\n\n /** Accessible name of every toast's close button (forwarded to lc-toast). */\n readonly closeAriaLabel = input('Close notification');\n\n /** Toasts keyed by `${position}:${politeness}` in the order they were shown. */\n private readonly groups = computed(() => {\n const groups = new Map<string, Toast[]>();\n for (const toast of this.toastService.toasts()) {\n const key = `${toast.position}:${ToastOutletComponent.liveFor(toast)}`;\n const group = groups.get(key);\n if (group) {\n group.push(toast);\n } else {\n groups.set(key, [toast]);\n }\n }\n return groups;\n });\n\n /**\n * 3.33 (request 052, 045-n2): per `bottom-*` stack, the live level of its\n * newest toast. That region gets `lc-toast-outlet__region--latest` and is\n * laid out at the edge, so the newest toast sits nearest the edge (and, in\n * a scrolling stack, in view at rest). DOM and announcement order stay.\n */\n protected readonly latestLive = computed(() => {\n const latest = new Map<ToastPosition, ToastLive>();\n for (const toast of this.toastService.toasts()) {\n if (toast.position.startsWith('bottom-')) {\n latest.set(toast.position, ToastOutletComponent.liveFor(toast));\n }\n }\n return latest;\n });\n\n protected toastsFor(position: ToastPosition, live: ToastLive): readonly Toast[] {\n return this.groups().get(`${position}:${live}`) ?? [];\n }\n\n protected onClosed(id: string): void {\n this.toastService.close(id);\n }\n\n /** Errors and warnings interrupt (assertive), everything else waits its turn. */\n private static liveFor(toast: Toast): ToastLive {\n return toast.variant === 'error' || toast.variant === 'warning' ? 'assertive' : 'polite';\n }\n}\n","@for (position of positions; track position) {\n <div class=\"lc-toast-outlet__stack\" [class]=\"'lc-toast-outlet__stack lc-toast-outlet__stack--' + position\">\n <!-- Both regions are always present (even empty) so that toasts inserted\n later are announced; the toasts themselves do not announce again. -->\n @for (live of liveLevels; track live) {\n <div\n class=\"lc-toast-outlet__region\"\n [class.lc-toast-outlet__region--latest]=\"latestLive().get(position) === live\"\n [attr.aria-live]=\"live\"\n aria-atomic=\"false\"\n >\n @for (toast of toastsFor(position, live); track toast.id) {\n <lc-toast [toast]=\"toast\" [announce]=\"false\" [closeAriaLabel]=\"closeAriaLabel()\" (closed)=\"onClosed($event)\" />\n }\n </div>\n }\n </div>\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-toast.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/toast/toast.service.ts","../../../../libs/angular-ui-kit/src/lib/toast/toast.component.ts","../../../../libs/angular-ui-kit/src/lib/toast/toast.component.html","../../../../libs/angular-ui-kit/src/lib/toast/toast-outlet.component.ts","../../../../libs/angular-ui-kit/src/lib/toast/toast-outlet.component.html"],"sourcesContent":["import { Injectable, PLATFORM_ID, inject, signal, Signal } from '@angular/core';\nimport { isPlatformBrowser } from '@angular/common';\n\nexport type ToastVariant = 'success' | 'error' | 'warning' | 'info';\nexport type ToastPosition =\n | 'top-left'\n | 'top-center'\n | 'top-right'\n | 'bottom-left'\n | 'bottom-center'\n | 'bottom-right';\n\nexport interface ToastAction {\n label: string;\n onClick: () => void;\n}\n\nexport interface ToastConfig {\n message: string;\n variant?: ToastVariant;\n position?: ToastPosition;\n duration?: number;\n showCloseButton?: boolean;\n action?: ToastAction;\n}\n\nexport interface Toast extends Required<Omit<ToastConfig, 'action'>> {\n id: string;\n action?: ToastAction;\n}\n\n/**\n * Toast service for showing ephemeral notifications.\n *\n * The toasts are rendered by `<lc-toast-outlet />`, which the application\n * places once (e.g. in its shell); without it nothing is shown. The options,\n * their defaults, the timing and how a toast is announced to screen readers\n * are documented under *Feedback/Toast Outlet* (3.17).\n *\n * @example\n * ```typescript\n * private readonly toastService = inject(ToastService);\n *\n * showSuccess() {\n * this.toastService.show({\n * message: 'Changes saved successfully!',\n * variant: 'success',\n * duration: 3000\n * });\n * }\n * ```\n */\n@Injectable({\n providedIn: 'root',\n})\nexport class ToastService {\n /**\n * Public readonly signal for toasts\n */\n public readonly toasts: Signal<readonly Toast[]>;\n\n /**\n * Internal signal for toast list\n */\n private readonly toastList = signal<Toast[]>([]);\n\n private readonly MAX_TOASTS = 5;\n private toastIdCounter = 0;\n private activeTimeouts = new Map<string, ReturnType<typeof setTimeout>>();\n /** Auto-dismiss timers only make sense in the browser (and `window` does not exist on the server). */\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n constructor() {\n this.toasts = this.toastList.asReadonly();\n }\n\n /**\n * Show a toast notification\n */\n show(config: ToastConfig): string {\n const toast: Toast = {\n id: this.generateId(),\n message: config.message,\n variant: config.variant || 'info',\n position: config.position || 'top-right',\n duration: config.duration !== undefined ? config.duration : 3000,\n showCloseButton: config.showCloseButton !== undefined ? config.showCloseButton : true,\n action: config.action,\n };\n\n // Add toast to list\n let currentToasts = this.toastList();\n\n // Remove oldest toast if at max capacity\n if (currentToasts.length >= this.MAX_TOASTS) {\n const oldestToast = currentToasts[0];\n if (oldestToast) {\n this.clearTimeout(oldestToast.id);\n currentToasts = currentToasts.slice(1);\n }\n }\n\n this.toastList.set([...currentToasts, toast]);\n\n // Auto-dismiss if duration > 0\n if (toast.duration > 0 && this.isBrowser) {\n const timeoutId = setTimeout(() => {\n this.close(toast.id);\n }, toast.duration);\n\n this.activeTimeouts.set(toast.id, timeoutId);\n }\n\n return toast.id;\n }\n\n /**\n * Close a specific toast\n */\n close(id: string): void {\n this.removeToast(id);\n }\n\n /**\n * Close all toasts\n */\n closeAll(): void {\n const currentToasts = this.toastList();\n currentToasts.forEach((toast) => {\n this.clearTimeout(toast.id);\n });\n this.toastList.set([]);\n }\n\n /**\n * Generate unique toast ID\n */\n private generateId(): string {\n return `toast-${++this.toastIdCounter}-${Date.now()}`;\n }\n\n /**\n * Remove a toast from the list\n */\n private removeToast(id: string): void {\n this.clearTimeout(id);\n const currentToasts = this.toastList();\n this.toastList.set(currentToasts.filter((t) => t.id !== id));\n }\n\n /**\n * Clear timeout for a toast\n */\n private clearTimeout(id: string): void {\n const timeoutId = this.activeTimeouts.get(id);\n if (timeoutId !== undefined) {\n clearTimeout(timeoutId);\n this.activeTimeouts.delete(id);\n }\n }\n}\n","import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n computed,\n ViewEncapsulation,\n} from '@angular/core';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport {\n ICON_CHECK_CIRCLE,\n ICON_CIRCLE_X,\n ICON_EXCLAMATION_TRIANGLE,\n ICON_INFORMATION_CIRCLE,\n ICON_X_MARK,\n} from '@lifecorner/angular-ui-kit/icons';\nimport type { Toast, ToastVariant } from './toast.service';\n\n/**\n * Toast component for displaying ephemeral notification messages.\n *\n * Features:\n * - Semantic variants (success, warning, error, info)\n * - Auto-dismiss with configurable duration\n * - Manual dismiss with close button\n * - Icon display per variant\n * - Stacked toast positioning via ToastService + `<lc-toast-outlet />`\n * - Animated enter/exit transitions\n *\n * Usually rendered by `<lc-toast-outlet />`; can also be placed directly:\n *\n * @example\n * ```html\n * <lc-toast [toast]=\"toast\" (closed)=\"dismiss($event)\" />\n * ```\n */\n@Component({\n selector: 'lc-toast',\n standalone: true,\n imports: [IconComponent],\n viewProviders: [\n ɵprovideKitIcons([ICON_X_MARK, ICON_CHECK_CIRCLE, ICON_CIRCLE_X, ICON_EXCLAMATION_TRIANGLE, ICON_INFORMATION_CIRCLE]),\n ],\n templateUrl: './toast.component.html',\n styleUrls: ['./toast.component.scss'],\n encapsulation: ViewEncapsulation.None, // Required for dynamic variant class styling\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class]': 'hostClasses()',\n '[attr.role]': 'ariaRole()',\n '[attr.aria-live]': 'ariaLive()',\n '[attr.aria-atomic]': 'announce() ? \"true\" : null',\n },\n})\nexport class ToastComponent {\n /**\n * Toast data\n */\n toast = input.required<Toast>();\n\n /**\n * Whether the toast is its own live region (`role=\"status\"`/`\"alert\"` on the\n * host). `lc-toast-outlet` sets this to false because its persistent live\n * regions already announce the toast — announcing twice would be noise.\n * @default true\n */\n announce = input<boolean>(true);\n\n /** Accessible name of the close button (`toast.showCloseButton`). */\n closeAriaLabel = input('Close notification');\n\n /**\n * Emitted when toast is closed\n */\n readonly closed = output<string>();\n\n /**\n * Computed host classes\n */\n protected hostClasses = computed(() => {\n const toast = this.toast();\n return `lc-toast lc-toast--${toast.variant}`;\n });\n\n /**\n * Computed container classes\n */\n protected containerClasses = computed(() => {\n return 'lc-toast__container';\n });\n\n /**\n * Computed ARIA role\n */\n protected ariaRole = computed(() => {\n if (!this.announce()) return null;\n const variant = this.toast().variant;\n return variant === 'error' || variant === 'warning' ? 'alert' : 'status';\n });\n\n /**\n * Computed ARIA live region priority\n */\n protected ariaLive = computed(() => {\n if (!this.announce()) return null;\n const variant = this.toast().variant;\n return variant === 'error' || variant === 'warning' ? 'assertive' : 'polite';\n });\n\n /**\n * Computed default icon based on variant\n */\n protected defaultIcon = computed(() => {\n const icons: Record<ToastVariant, string> = {\n success: 'check-circle',\n error: 'x-circle',\n warning: 'exclamation-triangle',\n info: 'information-circle',\n };\n return icons[this.toast().variant];\n });\n\n /**\n * Handle close button click\n */\n protected onCloseClick(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n this.closed.emit(this.toast().id);\n }\n\n /**\n * Handle action button click\n */\n protected onActionClick(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n const action = this.toast().action;\n if (action) {\n action.onClick();\n this.closed.emit(this.toast().id);\n }\n }\n}\n","<div [class]=\"containerClasses()\">\n <div class=\"lc-toast__icon\">\n <lc-icon [name]=\"defaultIcon()\" size=\"md\" [decorative]=\"true\" />\n </div>\n \n <div class=\"lc-toast__message\">\n {{ toast().message }}\n </div>\n \n @if (toast().action) {\n <button\n type=\"button\"\n class=\"lc-toast__action\"\n (click)=\"onActionClick($event)\"\n >\n {{ toast().action?.label }}\n </button>\n }\n \n @if (toast().showCloseButton) {\n <button\n type=\"button\"\n class=\"lc-toast__close\"\n [attr.aria-label]=\"closeAriaLabel()\"\n (click)=\"onCloseClick($event)\"\n >\n <lc-icon name=\"x-mark\" size=\"sm\" [decorative]=\"true\" />\n </button>\n }\n</div>\n","import { Component, ChangeDetectionStrategy, computed, inject, input } from '@angular/core';\nimport { OverlayInsetsService } from '@lifecorner/angular-ui-kit/internal/overlay';\nimport { ToastComponent } from './toast.component';\nimport { ToastService, type Toast, type ToastPosition } from './toast.service';\n\n/** Politeness of the live region a toast is announced from. */\ntype ToastLive = 'polite' | 'assertive';\n\nconst POSITIONS: readonly ToastPosition[] = [\n 'top-left',\n 'top-center',\n 'top-right',\n 'bottom-left',\n 'bottom-center',\n 'bottom-right',\n];\n\n/**\n * Renders the toasts of {@link ToastService}. Place it once in the application\n * shell; without it `ToastService.show()` has no visible effect.\n *\n * ```html\n * <lc-toast-outlet />\n * ```\n *\n * Toasts are stacked per `position`. Every position owns two live regions that\n * exist from the start — screen readers only announce content that is inserted\n * into an *existing* live region — one `polite` for success/info toasts and one\n * `assertive` for error/warning toasts. Dismissing a toast (close button,\n * action, auto-dismiss) removes it from the service.\n *\n * Offsets (3.28, AS-34): with `lc-app-shell` in the app (the outlet may sit\n * before or after it), the `top-*` stacks start below the shell's header and\n * the `bottom-*` stacks end above its bottom bar, each with the stack's 16 px\n * padding as the gap. The shell measures both in the browser (the header's\n * bottom edge with the top inset; the shown bar's top edge, from the\n * viewport's bottom, with the bottom inset). From 1024 px, where the bar is\n * hidden, the bottom offset is the safe-area inset. Without a shell, and in\n * prerendered HTML, both are `0px`, as before. Every stack is at most as high\n * as the space between the offsets and scrolls when its toasts need more\n * (200 % text), so each toast stays reachable.\n *\n * Bottom stacks show the newest toast nearest the edge (3.33). A top stack\n * shows its assertive region (error, warning) above its polite one (success,\n * info), each oldest first, so a newer error sits above an older success\n * (3.35, 053-n2). The toasts of a stack are 8 px (`--spacing-2`) apart\n * (3.33.1), within a live region and across the two; an empty region and the\n * last toast add no space, and the stack keeps its 16 px padding. A `top-*`\n * stack lies over the page on purpose (a toast stays visible wherever the\n * page is scrolled), so in the shell it can cover a title right under the\n * header (at 360 px a toast at y 72 over an h1 at y 80): prefer `bottom-*`\n * there.\n *\n * CSS hooks (set them on `lc-toast-outlet` or any ancestor, e.g. `:root`;\n * each wins over the shell's value; write lengths, `0px` rather than `0`):\n * - `--lc-toast-outlet-offset-top` — the space kept free above the `top-*`\n * stacks. Default `0px`; with `lc-app-shell`: its header's bottom edge, or\n * `env(safe-area-inset-top, 0px)` without a header.\n * - `--lc-toast-outlet-offset-bottom` — the space kept free below the\n * `bottom-*` stacks. Default `0px`; with `lc-app-shell`: the shown bottom\n * bar's top edge, measured from the viewport's bottom, or\n * `env(safe-area-inset-bottom, 0px)` when no bar shows.\n */\n@Component({\n selector: 'lc-toast-outlet',\n standalone: true,\n imports: [ToastComponent],\n templateUrl: './toast-outlet.component.html',\n styleUrls: ['./toast-outlet.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n // The shell's measured offsets (AS-34), private; `null` without a shell,\n // so the host gets no style attribute. The public hooks win in the CSS.\n '[style.--_lc-toast-outlet-frame-top]': 'insets.top()',\n '[style.--_lc-toast-outlet-frame-bottom]': 'insets.bottom()',\n },\n})\nexport class ToastOutletComponent {\n protected readonly positions = POSITIONS;\n protected readonly liveLevels: readonly ToastLive[] = ['assertive', 'polite'];\n\n private readonly toastService = inject(ToastService);\n protected readonly insets = inject(OverlayInsetsService);\n\n /** Accessible name of every toast's close button (forwarded to lc-toast). */\n readonly closeAriaLabel = input('Close notification');\n\n /** Toasts keyed by `${position}:${politeness}` in the order they were shown. */\n private readonly groups = computed(() => {\n const groups = new Map<string, Toast[]>();\n for (const toast of this.toastService.toasts()) {\n const key = `${toast.position}:${ToastOutletComponent.liveFor(toast)}`;\n const group = groups.get(key);\n if (group) {\n group.push(toast);\n } else {\n groups.set(key, [toast]);\n }\n }\n return groups;\n });\n\n /**\n * 3.33 (request 052, 045-n2): per `bottom-*` stack, the live level of its\n * newest toast. That region gets `lc-toast-outlet__region--latest` and is\n * laid out at the edge, so the newest toast sits nearest the edge (and, in\n * a scrolling stack, in view at rest). DOM and announcement order stay.\n */\n protected readonly latestLive = computed(() => {\n const latest = new Map<ToastPosition, ToastLive>();\n for (const toast of this.toastService.toasts()) {\n if (toast.position.startsWith('bottom-')) {\n latest.set(toast.position, ToastOutletComponent.liveFor(toast));\n }\n }\n return latest;\n });\n\n protected toastsFor(position: ToastPosition, live: ToastLive): readonly Toast[] {\n return this.groups().get(`${position}:${live}`) ?? [];\n }\n\n protected onClosed(id: string): void {\n this.toastService.close(id);\n }\n\n /** Errors and warnings interrupt (assertive), everything else waits its turn. */\n private static liveFor(toast: Toast): ToastLive {\n return toast.variant === 'error' || toast.variant === 'warning' ? 'assertive' : 'polite';\n }\n}\n","@for (position of positions; track position) {\n <div class=\"lc-toast-outlet__stack\" [class]=\"'lc-toast-outlet__stack lc-toast-outlet__stack--' + position\">\n <!-- Both regions are always present (even empty) so that toasts inserted\n later are announced; the toasts themselves do not announce again. -->\n @for (live of liveLevels; track live) {\n <div\n class=\"lc-toast-outlet__region\"\n [class.lc-toast-outlet__region--latest]=\"latestLive().get(position) === live\"\n [attr.aria-live]=\"live\"\n aria-atomic=\"false\"\n >\n @for (toast of toastsFor(position, live); track toast.id) {\n <lc-toast [toast]=\"toast\" [announce]=\"false\" [closeAriaLabel]=\"closeAriaLabel()\" (closed)=\"onClosed($event)\" />\n }\n </div>\n }\n </div>\n}\n"],"mappings":";;;;;;AAuDA,IAAa,eAAb,MAAa,aAAY;CAIP;CAKC,YAAY,OAAgB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAE/B,aAAa;CACtB,iBAAiB;CACjB,iCAAiB,IAAI,IAAG;CAEf,YAAY,kBAAkB,OAAO,WAAW,CAAC;CAElE,cAAA;EACE,KAAK,SAAS,KAAK,UAAU,WAAU;CACzC;CAKA,KAAK,QAAmB;EACtB,MAAM,QAAe;GACnB,IAAI,KAAK,WAAU;GACnB,SAAS,OAAO;GAChB,SAAS,OAAO,WAAW;GAC3B,UAAU,OAAO,YAAY;GAC7B,UAAU,OAAO,aAAa,SAAY,OAAO,WAAW;GAC5D,iBAAiB,OAAO,oBAAoB,SAAY,OAAO,kBAAkB;GACjF,QAAQ,OAAO;EAChB;EAGD,IAAI,gBAAgB,KAAK,UAAS;EAGlC,IAAI,cAAc,UAAU,KAAK,YAAY;GAC3C,MAAM,cAAc,cAAc;GAClC,IAAI,aAAa;IACf,KAAK,aAAa,YAAY,EAAE;IAChC,gBAAgB,cAAc,MAAM,CAAC;GACvC;EACF;EAEA,KAAK,UAAU,IAAI,CAAC,GAAG,eAAe,KAAK,CAAC;EAG5C,IAAI,MAAM,WAAW,KAAK,KAAK,WAAW;GACxC,MAAM,YAAY,iBAAgB;IAChC,KAAK,MAAM,MAAM,EAAE;GACrB,GAAG,MAAM,QAAQ;GAEjB,KAAK,eAAe,IAAI,MAAM,IAAI,SAAS;EAC7C;EAEA,OAAO,MAAM;CACf;CAKA,MAAM,IAAU;EACd,KAAK,YAAY,EAAE;CACrB;CAKA,WAAQ;EAEN,AADsB,KAAK,UAC3B,CAAA,CAAc,SAAS,UAAS;GAC9B,KAAK,aAAa,MAAM,EAAE;EAC5B,CAAC;EACD,KAAK,UAAU,IAAI,CAAA,CAAE;CACvB;CAKQ,aAAU;EAChB,OAAO,SAAS,EAAE,KAAK,eAAc,GAAI,KAAK,IAAG;CACnD;CAKQ,YAAY,IAAU;EAC5B,KAAK,aAAa,EAAE;EACpB,MAAM,gBAAgB,KAAK,UAAS;EACpC,KAAK,UAAU,IAAI,cAAc,QAAQ,MAAM,EAAE,OAAO,EAAE,CAAC;CAC7D;CAKQ,aAAa,IAAU;EAC7B,MAAM,YAAY,KAAK,eAAe,IAAI,EAAE;EAC5C,IAAI,cAAc,QAAW;GAC3B,aAAa,SAAS;GACtB,KAAK,eAAe,OAAO,EAAE;EAC/B;CACF;CAxGW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAY,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAZ,OAAA,QAAA,GAAA,sBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAY,YAFX;CAAM,CAAA;;AAEP,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAY,YAAA,CAAA;EAHxB,MAAA;EAAW,MAAA,CAAA,EACV,YAAY,OACb,CAAA;;;;ACAD,IAAa,iBAAb,MAAa,eAAc;CAIzB,QAAQ,MAAM,SAAiB,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAQ/B,WAAW,MAAe,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAG/B,iBAAiB,MAAM,sBAAqB,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAKnC,SAAS,OAAM;CAKd,cAAc,eAAc;EAEpC,OAAO,sBADO,KAAK,MACU,CAAA,CAAM;CACrC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAKQ,mBAAmB,eAAc;EACzC,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAKQ,WAAW,eAAc;EACjC,IAAI,CAAC,KAAK,SAAQ,GAAI,OAAO;EAC7B,MAAM,UAAU,KAAK,MAAK,CAAE,CAAC;EAC7B,OAAO,YAAY,WAAW,YAAY,YAAY,UAAU;CAClE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAKQ,WAAW,eAAc;EACjC,IAAI,CAAC,KAAK,SAAQ,GAAI,OAAO;EAC7B,MAAM,UAAU,KAAK,MAAK,CAAE,CAAC;EAC7B,OAAO,YAAY,WAAW,YAAY,YAAY,cAAc;CACtE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAKQ,cAAc,eAAc;EAOpC,OAAO;GALL,SAAS;GACT,OAAO;GACP,SAAS;GACT,MAAM;EAED,EAAM,KAAK,MAAK,CAAE,CAAC;CAC5B,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAKQ,aAAa,OAAY;EACjC,MAAM,eAAc;EACpB,MAAM,gBAAe;EACrB,KAAK,OAAO,KAAK,KAAK,MAAK,CAAE,CAAC,EAAE;CAClC;CAKU,cAAc,OAAY;EAClC,MAAM,eAAc;EACpB,MAAM,gBAAe;EACrB,MAAM,SAAS,KAAK,MAAK,CAAE,CAAC;EAC5B,IAAI,QAAQ;GACV,OAAO,QAAO;GACd,KAAK,OAAO,KAAK,KAAK,MAAK,CAAE,CAAC,EAAE;EAClC;CACF;CAxFW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAc,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAd,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAc,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,gBAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA,EAAA,QAAA,SAAA;EAAA,MAAA,EAAA,YAAA;GAAA,SAAA;GAAA,aAAA;GAAA,kBAAA;GAAA,oBAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UCtD3B;EA8BA,QAAA,CAAA,o3HAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MDSY;GAAa,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;GAAA;EAAA,CAAA;EAAA,eACR,CACb,iBAAiB;GAAC;GAAa;GAAmB;GAAe;GAA2B;EAAuB,CAAC,CACrH;EAAA,iBAAA,GAAA,wBAAA;EAAA,eAAA,GAAA,kBAAA;CAAA,CAAA;;AAYU,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAc,YAAA,CAAA;EAlB1B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAU,YACR;GAAI,SACP,CAAC,aAAa;GAAC,eACT,CACb,iBAAiB;IAAC;IAAa;IAAmB;IAAe;IAA2B;GAAuB,CAAC,CACrH;GAAA,eAGc,kBAAkB;GAAI,iBACpB,wBAAwB;GAAM,MACzC;IACJ,WAAW;IACX,eAAe;IACf,oBAAoB;IACpB,sBAAsB;GACvB;GAAA,UAAA;GAAA,QAAA,CAAA,o3HAAA;EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AE5CH,MAAM,YAAsC;CAC1C;CACA;CACA;CACA;CACA;CACA;AACD;AA8DD,IAAa,uBAAb,MAAa,qBAAoB;CACZ,YAAY;CACZ,aAAmC,CAAC,aAAa,QAAQ;CAE3D,eAAe,OAAO,YAAY;CAChC,SAAS,OAAO,oBAAoB;CAG9C,iBAAiB,MAAM,sBAAqB,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAGpC,SAAS,eAAc;EACtC,MAAM,yBAAS,IAAI,IAAG;EACtB,KAAK,MAAM,SAAS,KAAK,aAAa,OAAM,GAAI;GAC9C,MAAM,MAAM,GAAG,MAAM,SAAQ,GAAI,qBAAqB,QAAQ,KAAK;GACnE,MAAM,QAAQ,OAAO,IAAI,GAAG;GAC5B,IAAI,OACF,MAAM,KAAK,KAAK;QAEhB,OAAO,IAAI,KAAK,CAAC,KAAK,CAAC;EAE3B;EACA,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAQiB,aAAa,eAAc;EAC5C,MAAM,yBAAS,IAAI,IAAG;EACtB,KAAK,MAAM,SAAS,KAAK,aAAa,OAAM,GAC1C,IAAI,MAAM,SAAS,WAAW,SAAS,GACrC,OAAO,IAAI,MAAM,UAAU,qBAAqB,QAAQ,KAAK,CAAC;EAGlE,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAEQ,UAAU,UAAyB,MAAe;EAC1D,OAAO,KAAK,OAAM,CAAE,CAAC,IAAI,GAAG,SAAQ,GAAI,MAAM,KAAK,CAAA;CACrD;CAEU,SAAS,IAAU;EAC3B,KAAK,aAAa,MAAM,EAAE;CAC5B;CAGQ,OAAO,QAAQ,OAAY;EACjC,OAAO,MAAM,YAAY,WAAW,MAAM,YAAY,YAAY,cAAc;CAClF;CApDW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAoB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAApB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAoB,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,gBAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,MAAA,EAAA,YAAA;GAAA,sCAAA;GAAA,yCAAA;EAAA,EAAA;EAAA,UAAA;EAAA,UC7EjC;EAkBA,QAAA,CAAA,gnEAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MDgDY;GAAc,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;GAAA;GAAA,SAAA,CAAA,QAAA;EAAA,CAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAWb,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAoB,YAAA,CAAA;EAdhC,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAiB,YACf;GAAI,SACP,CAAC,cAAc;GAAC,iBAGR,wBAAwB;GAAM,MACzC;IAGJ,wCAAwC;IACxC,2CAA2C;GAC5C;GAAA,UAAA;GAAA,QAAA,CAAA,gnEAAA;EAAA,CAAA"}
|
|
@@ -54,6 +54,7 @@ export * from "@lifecorner/angular-ui-kit/app-shell";
|
|
|
54
54
|
export * from "@lifecorner/angular-ui-kit/avatar";
|
|
55
55
|
export * from "@lifecorner/angular-ui-kit/badge";
|
|
56
56
|
export * from "@lifecorner/angular-ui-kit/status-dot";
|
|
57
|
+
export * from "@lifecorner/angular-ui-kit/state-strip";
|
|
57
58
|
export * from "@lifecorner/angular-ui-kit/toggle-group";
|
|
58
59
|
export * from "@lifecorner/angular-ui-kit/list";
|
|
59
60
|
export * from "@lifecorner/angular-ui-kit/chip";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lifecorner/angular-ui-kit",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.36.0",
|
|
4
4
|
"description": "LifeCorner Design System – Angular UI component library",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -462,6 +462,10 @@
|
|
|
462
462
|
"types": "./types/lifecorner-angular-ui-kit-stat-trend.d.ts",
|
|
463
463
|
"default": "./fesm2022/lifecorner-angular-ui-kit-stat-trend.mjs"
|
|
464
464
|
},
|
|
465
|
+
"./state-strip": {
|
|
466
|
+
"types": "./types/lifecorner-angular-ui-kit-state-strip.d.ts",
|
|
467
|
+
"default": "./fesm2022/lifecorner-angular-ui-kit-state-strip.mjs"
|
|
468
|
+
},
|
|
465
469
|
"./status-dot": {
|
|
466
470
|
"types": "./types/lifecorner-angular-ui-kit-status-dot.d.ts",
|
|
467
471
|
"default": "./fesm2022/lifecorner-angular-ui-kit-status-dot.mjs"
|
|
@@ -1647,6 +1647,8 @@ describe('Component pairings of 3.25.0 (request 039)', () => {
|
|
|
1647
1647
|
['textarea', '.lc-textarea--error:focus', '2px solid var(--color-error-600)', '0'],
|
|
1648
1648
|
['number', '.number-input--error .number-input__control:focus-within', '2px solid var(--color-error-600)', '0'],
|
|
1649
1649
|
['combobox', '.lc-combobox--error .lc-combobox__input-wrapper:focus-within', '2px solid var(--color-error-default)', '0'],
|
|
1650
|
+
// 3.35 (055 D-3): the rest focus ring, so `focus()` from code shows it too.
|
|
1651
|
+
['combobox', '.lc-combobox__input-wrapper:focus-within', primary, '0'],
|
|
1650
1652
|
];
|
|
1651
1653
|
|
|
1652
1654
|
it.each(rings)('AC-2: %s %s draws a solid 2 px outline, no halo', (sheet, selector, outline, offset) => {
|
|
@@ -1958,3 +1960,75 @@ describe('Component pairings of 3.30 (request 047)', () => {
|
|
|
1958
1960
|
expect(Math.min(got.textOnFill, got.textOnHoverFill)).toBeGreaterThanOrEqual(4.5);
|
|
1959
1961
|
});
|
|
1960
1962
|
});
|
|
1963
|
+
|
|
1964
|
+
/**
|
|
1965
|
+
* Request 056 (3.36, design 056 §5): the state strip's marks, ring and
|
|
1966
|
+
* caption, the ledger rules of the description-list total and the table
|
|
1967
|
+
* footer, and the band story's parts. Minima over the page, the surfaces and
|
|
1968
|
+
* a hovered row (translucent fills composited over the surface).
|
|
1969
|
+
*/
|
|
1970
|
+
describe('Component pairings of 3.36 (request 056)', () => {
|
|
1971
|
+
const lib = (path: string) => resolve(__dirname, '../lib', path);
|
|
1972
|
+
const sheets = {
|
|
1973
|
+
strip: compile(lib('state-strip/state-strip.component.scss')).css,
|
|
1974
|
+
dl: compile(lib('description-list/description-list.component.scss')).css,
|
|
1975
|
+
table: compile(lib('table/table.component.scss')).css,
|
|
1976
|
+
};
|
|
1977
|
+
const body = (sheet: keyof typeof sheets, selector: string) => {
|
|
1978
|
+
const css = sheets[sheet];
|
|
1979
|
+
const at = css.indexOf(`\n${selector} {`);
|
|
1980
|
+
expect([selector, at > -1]).toEqual([selector, true]);
|
|
1981
|
+
return css.slice(at, css.indexOf('}', at));
|
|
1982
|
+
};
|
|
1983
|
+
const floor = (n: number) => Math.floor(n * 100) / 100;
|
|
1984
|
+
const grounds = ['--color-background', '--color-surface', '--color-surface-2', '--color-surface-hover', '--color-surface-sunken'];
|
|
1985
|
+
|
|
1986
|
+
it('AC-4, AC-12, AC-19: the rules pair these tokens', () => {
|
|
1987
|
+
expect(body('strip', '.lc-state-strip__mark--success')).toContain('background-color: var(--color-text-success)');
|
|
1988
|
+
expect(body('strip', '.lc-state-strip__mark--warning')).toContain('background-color: var(--color-text-warning)');
|
|
1989
|
+
expect(body('strip', '.lc-state-strip__mark--error')).toContain('background-color: var(--color-text-error)');
|
|
1990
|
+
expect(body('strip', '.lc-state-strip__mark--neutral')).toContain('background-color: var(--color-field-border)');
|
|
1991
|
+
expect(body('strip', '.lc-state-strip__cell:focus-visible')).toContain('outline: 2px solid var(--color-primary-500)');
|
|
1992
|
+
const caption = body('strip', '.lc-state-strip__caption');
|
|
1993
|
+
expect(caption).toContain('background-color: var(--color-text-primary)');
|
|
1994
|
+
expect(caption).toContain('color: var(--color-surface)');
|
|
1995
|
+
expect(body('dl', '.lc-dl .lc-dl__row--total')).toContain('border-top: 1px solid var(--color-field-border)');
|
|
1996
|
+
expect(body('table', '.lc-table tfoot tr')).toContain('border-bottom: 3px double var(--color-field-border)');
|
|
1997
|
+
});
|
|
1998
|
+
|
|
1999
|
+
// [light, dark], floored; design 056 §5 quotes the rounded values (warning
|
|
2000
|
+
// 5.48 / 6.35, error 11.44, ring 3.97 / 7.58, caption 17.74 / 15.85).
|
|
2001
|
+
const expected = {
|
|
2002
|
+
success: [4.81, 6.97],
|
|
2003
|
+
warning: [5.47, 6.34],
|
|
2004
|
+
error: [11.43, 7.21],
|
|
2005
|
+
neutral: [4.39, 5.56],
|
|
2006
|
+
ring: [3.96, 7.57],
|
|
2007
|
+
caption: [17.73, 15.85],
|
|
2008
|
+
};
|
|
2009
|
+
|
|
2010
|
+
it.each(palettes.map(([name, tokens], i) => [name, tokens, i] as const))('AC-4, AC-12: %s palette: the design 056 §5 ratios', (_palette, tokens, i) => {
|
|
2011
|
+
const c = (name: string) => color(tokens, name);
|
|
2012
|
+
const surface = c('--color-surface');
|
|
2013
|
+
const ground = (name: string) => over(c(name), surface);
|
|
2014
|
+
const worst = (ink: string) => floor(Math.min(...grounds.map((g) => ratio(over(c(ink), ground(g)), ground(g)))));
|
|
2015
|
+
const got = {
|
|
2016
|
+
success: worst('--color-text-success'),
|
|
2017
|
+
warning: worst('--color-text-warning'),
|
|
2018
|
+
error: worst('--color-text-error'),
|
|
2019
|
+
neutral: worst('--color-field-border'),
|
|
2020
|
+
ring: worst('--color-primary-500'),
|
|
2021
|
+
caption: floor(ratio(c('--color-surface'), c('--color-text-primary'))),
|
|
2022
|
+
};
|
|
2023
|
+
expect(got).toEqual(Object.fromEntries(Object.entries(expected).map(([key, pair]) => [key, pair[i]])));
|
|
2024
|
+
// Marks, ring and rules: 3:1 (WCAG 1.4.11); the caption is text: 4.5:1.
|
|
2025
|
+
for (const key of ['success', 'warning', 'error', 'neutral', 'ring'] as const) expect(got[key]).toBeGreaterThanOrEqual(3);
|
|
2026
|
+
expect(got.caption).toBeGreaterThanOrEqual(4.5);
|
|
2027
|
+
});
|
|
2028
|
+
|
|
2029
|
+
it.each(palettes)('AC-16: %s palette: the band story\'s five part colours keep 3:1 on the surface', (_palette, tokens) => {
|
|
2030
|
+
const surface = color(tokens, '--color-surface');
|
|
2031
|
+
const parts = ['--color-primary-700', '--color-primary-500', '--color-info-default', '--color-secondary-700', '--color-neutral-500'];
|
|
2032
|
+
for (const part of parts) expect([part, ratio(over(color(tokens, part), surface), surface) >= 3]).toEqual([part, true]);
|
|
2033
|
+
});
|
|
2034
|
+
});
|
|
@@ -2,7 +2,10 @@ import * as i0 from "@angular/core";
|
|
|
2
2
|
export type AlertVariant = 'success' | 'error' | 'warning' | 'info';
|
|
3
3
|
/**
|
|
4
4
|
* Layout of the projected actions (`slot="action"`).
|
|
5
|
-
* - `inline`: one action right of the body, vertically centred (3.2)
|
|
5
|
+
* - `inline`: one action right of the body, vertically centred (3.2); from
|
|
6
|
+
* 16rem to 30rem inside the border (alerts of 258–481 px at 100 % text,
|
|
7
|
+
* 514–961 px at 200 %) a button action takes its own row below the text,
|
|
8
|
+
* lined up with it, at its natural width (3.35)
|
|
6
9
|
* - `stacked`: the actions in their own row below the title and message;
|
|
7
10
|
* below 576 px of alert width one per line at full width, 8 px apart,
|
|
8
11
|
* from 576 px side by side at their natural width
|
|
@@ -25,6 +28,10 @@ export type AlertActionsLayout = 'inline' | 'stacked';
|
|
|
25
28
|
* several actions stacked below it (`actionsLayout="stacked"`); 3.12: a text
|
|
26
29
|
* link (`<a slot="action" href="…">`) as the one way forward gets a
|
|
27
30
|
* 44 × 44 px target, link colour, an underline and a focus ring
|
|
31
|
+
* - 3.35: from 16rem to 30rem inside the border (alerts of 258–481 px at
|
|
32
|
+
* 100 % text, 514–961 px at 200 %) an inline button action takes its own
|
|
33
|
+
* row below the text, lined up with it, at its natural width, so the
|
|
34
|
+
* message keeps about 200 px beside the ×
|
|
28
35
|
* - 3.13.1: narrow layout below 16rem inside the border (alerts under 258 px
|
|
29
36
|
* at 100 % text, 514 px at 200 %): the icon shares the first row with the
|
|
30
37
|
* title, message and actions take the full width below, the padding is one
|
|
@@ -84,7 +91,10 @@ export declare class AlertComponent {
|
|
|
84
91
|
iconAriaLabel: import("@angular/core").InputSignal<string | undefined>;
|
|
85
92
|
/**
|
|
86
93
|
* Layout of the projected actions (`slot="action"`): `inline` — one action
|
|
87
|
-
* right of the body (3.2);
|
|
94
|
+
* right of the body (3.2); from 16rem to 30rem inside the border (alerts of
|
|
95
|
+
* 258–481 px at 100 % text, 514–961 px at 200 %) a button action takes its
|
|
96
|
+
* own row below the text, lined up with it, at its natural width (3.35);
|
|
97
|
+
* `stacked` — the actions in their own row below
|
|
88
98
|
* the title and message, one per line at full width and 8 px apart below
|
|
89
99
|
* 576 px of alert width, side by side at their natural width from there.
|
|
90
100
|
* @default 'inline'
|
|
@@ -138,7 +138,11 @@ export declare class BottomNavComponent {
|
|
|
138
138
|
* destinations' badges; pass the value to show. It sits on the bar's last
|
|
139
139
|
* entry; values up to three characters (`'99+'`) fit: on the last entry a
|
|
140
140
|
* badge that would pass the entry's edge moves left until it ends there
|
|
141
|
-
* (3.33). `null` or `undefined`: no badge.
|
|
141
|
+
* (3.33). `null` or `undefined`: no badge. Known limit (3.35, 052-n3):
|
|
142
|
+
* '99+' on the last entry of a five-entry bar at 360 px starts 3.2 px
|
|
143
|
+
* (docked) / 3.4 px (floating) left of the pill centre and covers two of the
|
|
144
|
+
* More glyph's three dots; the label and the read badge text still name the
|
|
145
|
+
* entry.
|
|
142
146
|
*
|
|
143
147
|
* @default null
|
|
144
148
|
*/
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
2
|
import { ElementRef } from "@angular/core";
|
|
3
|
-
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'link' | 'danger' | 'warning' | 'info' | 'inverse';
|
|
3
|
+
export type ButtonVariant = 'primary' | 'secondary' | 'outline' | 'ghost' | 'link' | 'danger' | 'warning' | 'info' | 'inverse' | 'inverse-outline';
|
|
4
4
|
export type ButtonSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
5
5
|
export type ButtonType = 'button' | 'submit' | 'reset';
|
|
6
6
|
/**
|
|
@@ -15,7 +15,9 @@ export declare class ButtonComponent {
|
|
|
15
15
|
* such as the default `lc-hero` bands (primary, neutral, info, accent-purple,
|
|
16
16
|
* accent-violet). It looks the same in both themes. Not for light backgrounds
|
|
17
17
|
* or `variant="light"` heroes. CSS hook `--lc-button-inverse-fg` (default
|
|
18
|
-
* `#0d353d`) sets its ink; keep 4.5:1 on white.
|
|
18
|
+
* `#0d353d`) sets its ink; keep 4.5:1 on white. `inverse-outline` (3.36) is
|
|
19
|
+
* the quieter action beside it on the same bands: white text and keyline on
|
|
20
|
+
* a dark translucent fill, the same sizes, height, icon slots and states.
|
|
19
21
|
* @default 'primary'
|
|
20
22
|
*/
|
|
21
23
|
readonly variant: import("@angular/core").InputSignal<ButtonVariant>;
|
|
@@ -239,7 +241,9 @@ export declare class ButtonLinkComponent {
|
|
|
239
241
|
* such as the default `lc-hero` bands (primary, neutral, info, accent-purple,
|
|
240
242
|
* accent-violet). It looks the same in both themes. Not for light backgrounds
|
|
241
243
|
* or `variant="light"` heroes. CSS hook `--lc-button-inverse-fg` (default
|
|
242
|
-
* `#0d353d`) sets its ink; keep 4.5:1 on white.
|
|
244
|
+
* `#0d353d`) sets its ink; keep 4.5:1 on white. `inverse-outline` (3.36) is
|
|
245
|
+
* the quieter link beside it on the same bands: white text and keyline on a
|
|
246
|
+
* dark translucent fill, the same sizes and height.
|
|
243
247
|
* @default 'primary'
|
|
244
248
|
*/
|
|
245
249
|
readonly variant: import("@angular/core").InputSignal<ButtonVariant>;
|
|
@@ -19,6 +19,8 @@ export type CardFooterLayout = 'default' | 'equal';
|
|
|
19
19
|
* the title stays a heading
|
|
20
20
|
* - Equal footer (3.29): `footerLayout="equal"` gives two answers of equal
|
|
21
21
|
* weight in the `[card-footer]` slot the same width
|
|
22
|
+
* - Collapsible (3.36): `collapsible` with `[(expanded)]` turns the head into
|
|
23
|
+
* one toggle that opens and closes the body and footer
|
|
22
24
|
*
|
|
23
25
|
* @example
|
|
24
26
|
* ```html
|
|
@@ -181,23 +183,58 @@ export declare class CardComponent {
|
|
|
181
183
|
* @default 'default'
|
|
182
184
|
*/
|
|
183
185
|
footerLayout: import("@angular/core").InputSignal<CardFooterLayout>;
|
|
186
|
+
/**
|
|
187
|
+
* The card can close (3.36, regeln row 1): the head (icon, title, subtitle)
|
|
188
|
+
* becomes one toggle, a button inside the title's heading with
|
|
189
|
+
* `aria-expanded` and `aria-controls`, whose hit area is the whole head (at
|
|
190
|
+
* least 44 px high); Enter, Space or a click open and close the body and the
|
|
191
|
+
* `[card-footer]`. A chevron at the end of the head shows the state.
|
|
192
|
+
* `[card-header-action]` stays a separate control beside it. Needs the
|
|
193
|
+
* built-in `title` (otherwise ignored); wins over `clickable`, `href` and
|
|
194
|
+
* `route`, which are then ignored; ignored on `dashed`. Bind `[(expanded)]`.
|
|
195
|
+
* @default false
|
|
196
|
+
*/
|
|
197
|
+
collapsible: import("@angular/core").InputSignal<boolean>;
|
|
198
|
+
/**
|
|
199
|
+
* Open state of a `collapsible` card (3.36), two-way: `[(expanded)]`. Open
|
|
200
|
+
* by default, so a plain `collapsible` hides nothing; set `false` for a card
|
|
201
|
+
* that starts closed (also in prerendered HTML). Closed, only the head
|
|
202
|
+
* shows: the body is `hidden` and the footer is not displayed.
|
|
203
|
+
* @default true
|
|
204
|
+
*/
|
|
205
|
+
readonly expanded: import("@angular/core").ModelSignal<boolean>;
|
|
184
206
|
/**
|
|
185
207
|
* Emitted when a `clickable` card is clicked or activated with Enter or
|
|
186
208
|
* Space. Not emitted on a link card (`href`/`route`): the link navigates by
|
|
187
209
|
* itself (one navigation); bind the native `(click)` for analytics.
|
|
188
210
|
*/
|
|
189
211
|
readonly cardClick: import("@angular/core").OutputEmitterRef<MouseEvent>;
|
|
212
|
+
/** Generated id prefix (3.36): creation order, so prerendered HTML is the same in every build. */
|
|
213
|
+
private readonly uid;
|
|
214
|
+
/** Id of the body a collapsible card's toggle controls. */
|
|
215
|
+
protected readonly bodyId: string;
|
|
216
|
+
/** Id of the subtitle that describes a collapsible card's toggle. */
|
|
217
|
+
protected readonly subtitleId: string;
|
|
218
|
+
/**
|
|
219
|
+
* Whether the card collapses (3.36): `collapsible` with a built-in title,
|
|
220
|
+
* except for the dashed tile.
|
|
221
|
+
*/
|
|
222
|
+
protected readonly isCollapsible: import("@angular/core").Signal<boolean>;
|
|
190
223
|
/**
|
|
191
224
|
* How the card links (3.24): `href` wins over `route`; `''`/`null` routes
|
|
192
|
-
* are no link, and the dashed "coming soon" tile never links.
|
|
225
|
+
* are no link, and the dashed "coming soon" tile never links. A
|
|
226
|
+
* collapsible card (3.36) never links.
|
|
193
227
|
*/
|
|
194
228
|
protected readonly linkMode: import("@angular/core").Signal<"href" | "route" | null>;
|
|
195
229
|
/**
|
|
196
230
|
* Whether the card acts as a button: `clickable`, except for the dashed
|
|
197
|
-
* "coming soon" tile, which is never interactive,
|
|
198
|
-
* anchor is the only interactive element.
|
|
231
|
+
* "coming soon" tile, which is never interactive, a link card, whose
|
|
232
|
+
* anchor is the only interactive element, and a collapsible card (3.36),
|
|
233
|
+
* whose toggle is.
|
|
199
234
|
*/
|
|
200
235
|
protected isClickable: import("@angular/core").Signal<boolean>;
|
|
236
|
+
/** Opens or closes a collapsible card; `expandedChange` emits the new state. */
|
|
237
|
+
protected toggle(): void;
|
|
201
238
|
/** `ariaLabel` on the card; on a link card it names the anchor instead. */
|
|
202
239
|
protected readonly cardAriaLabel: import("@angular/core").Signal<string | undefined>;
|
|
203
240
|
constructor();
|
|
@@ -309,7 +346,18 @@ export declare class CardComponent {
|
|
|
309
346
|
"required": false;
|
|
310
347
|
"isSignal": true;
|
|
311
348
|
};
|
|
349
|
+
"collapsible": {
|
|
350
|
+
"alias": "collapsible";
|
|
351
|
+
"required": false;
|
|
352
|
+
"isSignal": true;
|
|
353
|
+
};
|
|
354
|
+
"expanded": {
|
|
355
|
+
"alias": "expanded";
|
|
356
|
+
"required": false;
|
|
357
|
+
"isSignal": true;
|
|
358
|
+
};
|
|
312
359
|
}, {
|
|
360
|
+
"expanded": "expandedChange";
|
|
313
361
|
"cardClick": "cardClick";
|
|
314
362
|
}, never, ["[card-badge]", "[card-header-action]", "[card-header]", "*", "[card-footer]"], true, never>;
|
|
315
363
|
}
|
|
@@ -25,6 +25,10 @@ export type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg';
|
|
|
25
25
|
* (`[(selectedValue)]`, single mode), next to the `valueChange` output with
|
|
26
26
|
* the option object and the forms binding.
|
|
27
27
|
*
|
|
28
|
+
* `focus()` (3.35) moves the focus into the field's `<input>` when a form
|
|
29
|
+
* opens or after a rejected save (WCAG 2.4.3); it opens the list as a user's
|
|
30
|
+
* focus does (`openOnFocus`).
|
|
31
|
+
*
|
|
28
32
|
* @example
|
|
29
33
|
* ```html
|
|
30
34
|
* <lc-combobox
|
|
@@ -62,6 +66,16 @@ export declare class ComboboxComponent implements ControlValueAccessor {
|
|
|
62
66
|
readonly helperText: import("@angular/core").InputSignal<string | undefined>;
|
|
63
67
|
/** Error message */
|
|
64
68
|
readonly error: import("@angular/core").InputSignal<string | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Announce the error message the moment it appears (`role="alert"` on the
|
|
71
|
+
* message), as `lc-textarea`. Set `false` when an `lc-alert` error summary
|
|
72
|
+
* already announces the errors, e.g. a page that moves focus to this field
|
|
73
|
+
* after a failed submit (422): the error is then read once, with the field,
|
|
74
|
+
* not twice (alert and description). The message stays visible, stays linked
|
|
75
|
+
* through `aria-describedby`, and the input keeps `aria-invalid`.
|
|
76
|
+
* @default true
|
|
77
|
+
*/
|
|
78
|
+
readonly announceError: import("@angular/core").InputSignal<boolean>;
|
|
65
79
|
/** Disabled state */
|
|
66
80
|
readonly disabled: import("@angular/core").InputSignal<boolean>;
|
|
67
81
|
/** Allow multiple selections */
|
|
@@ -176,6 +190,23 @@ export declare class ComboboxComponent implements ControlValueAccessor {
|
|
|
176
190
|
registerOnChange(fn: (value: ComboboxValue) => void): void;
|
|
177
191
|
registerOnTouched(fn: () => void): void;
|
|
178
192
|
setDisabledState(isDisabled: boolean): void;
|
|
193
|
+
/**
|
|
194
|
+
* Moves the focus into the field's `<input>` (3.35), e.g. when a form opens
|
|
195
|
+
* with this field first, or to the field with the error after a rejected
|
|
196
|
+
* save (422) (WCAG 2.4.3). `options` as for `HTMLElement.focus()`
|
|
197
|
+
* (`{ preventScroll: true }`). Shows the same focus ring as a user's focus.
|
|
198
|
+
* Like a user's focus it opens the list when `openOnFocus` is `true` and
|
|
199
|
+
* there is something to show; with `false` the list stays closed
|
|
200
|
+
* (`aria-expanded="false"`). A disabled field takes no focus (it stays where
|
|
201
|
+
* it is). Call it once the field has rendered, e.g.
|
|
202
|
+
* `afterNextRender(() => this.month().focus(), { injector })` with
|
|
203
|
+
* `month = viewChild.required(ComboboxComponent)` and the page component's
|
|
204
|
+
* `injector = inject(Injector)`. In an `lc-modal` that opens with the field,
|
|
205
|
+
* that call runs after the dialog moved the focus to its first control.
|
|
206
|
+
* Does nothing before the component has rendered.
|
|
207
|
+
* @param options Passed to the native `focus()`.
|
|
208
|
+
*/
|
|
209
|
+
focus(options?: FocusOptions): void;
|
|
179
210
|
/**
|
|
180
211
|
* Clear the current selection and query. Emits `null` (single) or `[]`
|
|
181
212
|
* (multiple) exactly once, like a user-initiated deselect.
|
|
@@ -247,6 +278,11 @@ export declare class ComboboxComponent implements ControlValueAccessor {
|
|
|
247
278
|
"required": false;
|
|
248
279
|
"isSignal": true;
|
|
249
280
|
};
|
|
281
|
+
"announceError": {
|
|
282
|
+
"alias": "announceError";
|
|
283
|
+
"required": false;
|
|
284
|
+
"isSignal": true;
|
|
285
|
+
};
|
|
250
286
|
"disabled": {
|
|
251
287
|
"alias": "disabled";
|
|
252
288
|
"required": false;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { BadgeVariant } from "@lifecorner/angular-ui-kit/badge";
|
|
1
2
|
import * as i0 from "@angular/core";
|
|
2
3
|
/**
|
|
3
4
|
* Emphasis treatment applied to a row's value.
|
|
@@ -26,6 +27,24 @@ export interface DescriptionListItem {
|
|
|
26
27
|
datetime?: string;
|
|
27
28
|
/** Optional visual emphasis for the value. @default 'default' */
|
|
28
29
|
emphasis?: DescriptionListEmphasis;
|
|
30
|
+
/**
|
|
31
|
+
* Shows the value as an `lc-badge` (3.36, quellen row 2): rounded, `sm` in
|
|
32
|
+
* an md list, `xs` in an sm list. A `value` that is empty or the same word
|
|
33
|
+
* (trimmed, any case) is not shown; another value stays as text before the
|
|
34
|
+
* badge („1“ [Freigegeben]), and `href` or `datetime` wrap that text only.
|
|
35
|
+
* Term and value stay one `dt`/`dd` pair, read as „term, badge“.
|
|
36
|
+
*/
|
|
37
|
+
badge?: string;
|
|
38
|
+
/** Variant of the `badge`, as `lc-badge`. @default 'default' */
|
|
39
|
+
badgeVariant?: BadgeVariant;
|
|
40
|
+
/**
|
|
41
|
+
* The sum item (3.36, app-shell row 2): a rule above and a double rule
|
|
42
|
+
* below (`--color-field-border`), term and value semibold with tabular
|
|
43
|
+
* figures; its `emphasis` is ignored. `totalAriaLabel` is read before its
|
|
44
|
+
* term. Usually the last item.
|
|
45
|
+
* @default false
|
|
46
|
+
*/
|
|
47
|
+
total?: boolean;
|
|
29
48
|
/** Optional opaque payload echoed back in `itemClick`. */
|
|
30
49
|
id?: string;
|
|
31
50
|
}
|
|
@@ -55,6 +74,8 @@ export type DescriptionListSeparator = 'line' | 'divider' | 'none';
|
|
|
55
74
|
* - Semantic markup (`<dl>`/`<dt>`/`<dd>`) for accessibility; `clickable`
|
|
56
75
|
* rows hold a native button (named by term and value) that the keyboard
|
|
57
76
|
* reaches, and the `dl` keeps its term and value pairs.
|
|
77
|
+
* - 3.36: an item's value as a badge (`badge`, `badgeVariant`), and a sum
|
|
78
|
+
* item (`total`) with ledger rules, announced with `totalAriaLabel`.
|
|
58
79
|
*
|
|
59
80
|
* @example
|
|
60
81
|
* ```html
|
|
@@ -99,8 +120,22 @@ export declare class DescriptionListComponent {
|
|
|
99
120
|
* @default false
|
|
100
121
|
*/
|
|
101
122
|
readonly clickable: import("@angular/core").InputSignal<boolean>;
|
|
123
|
+
/**
|
|
124
|
+
* Read before the term of a `total` item and not shown (3.36, app-shell
|
|
125
|
+
* row 2): „Summe“ makes a screen reader read „Summe, Gesamtkosten Ist,
|
|
126
|
+
* 522.530,00 €“. Empty adds nothing.
|
|
127
|
+
* @default ''
|
|
128
|
+
*/
|
|
129
|
+
readonly totalAriaLabel: import("@angular/core").InputSignal<string>;
|
|
102
130
|
/** Emitted when a row is clicked (or activated via keyboard when `clickable`). */
|
|
103
131
|
readonly itemClick: import("@angular/core").OutputEmitterRef<DescriptionListItem>;
|
|
132
|
+
/** The visually hidden start of a total's term: „Summe, “ (3.36). */
|
|
133
|
+
protected readonly totalPrefix: import("@angular/core").Signal<string>;
|
|
134
|
+
/**
|
|
135
|
+
* Whether a badge item also shows its `value` as text (3.36, D-2): not when
|
|
136
|
+
* it is empty or the badge's word.
|
|
137
|
+
*/
|
|
138
|
+
protected badgeShowsValue(item: DescriptionListItem): boolean;
|
|
104
139
|
/** Generated id prefix, taken once per instance, so later ids don't shift. */
|
|
105
140
|
private readonly uid;
|
|
106
141
|
/** Id of row `index`'s term (only rendered when `clickable`). */
|
|
@@ -147,6 +182,11 @@ export declare class DescriptionListComponent {
|
|
|
147
182
|
"required": false;
|
|
148
183
|
"isSignal": true;
|
|
149
184
|
};
|
|
185
|
+
"totalAriaLabel": {
|
|
186
|
+
"alias": "totalAriaLabel";
|
|
187
|
+
"required": false;
|
|
188
|
+
"isSignal": true;
|
|
189
|
+
};
|
|
150
190
|
}, {
|
|
151
191
|
"itemClick": "itemClick";
|
|
152
192
|
}, never, never, true, never>;
|
|
@@ -12,7 +12,10 @@ export type DrawerSize = 'sm' | 'md' | 'lg' | 'xl';
|
|
|
12
12
|
* - Close on Escape key support
|
|
13
13
|
* - Heading text display
|
|
14
14
|
* - Content projection for arbitrary body content
|
|
15
|
-
* - Accessible with ARIA dialog role, focus trap and focus restore
|
|
15
|
+
* - Accessible with ARIA dialog role, focus trap and focus restore;
|
|
16
|
+
* `returnFocusTo` (3.35) names the element that gets the focus back after
|
|
17
|
+
* the drawer closed (WebKit doesn't focus a tapped button, so the one
|
|
18
|
+
* captured at open is `body`)
|
|
16
19
|
*
|
|
17
20
|
* @example
|
|
18
21
|
* ```html
|
|
@@ -42,6 +45,20 @@ export declare class DrawerComponent implements OnDestroy {
|
|
|
42
45
|
readonly ariaLabel: import("@angular/core").InputSignal<string>;
|
|
43
46
|
/** Accessible name of the close button. */
|
|
44
47
|
readonly closeAriaLabel: import("@angular/core").InputSignal<string>;
|
|
48
|
+
/**
|
|
49
|
+
* Element that gets the focus back after the drawer closed (3.35), instead
|
|
50
|
+
* of the one that had it at open. Set it to the trigger: WebKit (Safari,
|
|
51
|
+
* every iOS browser) doesn't focus a tapped button, so the captured element
|
|
52
|
+
* is `body`. Applied when the panel has left the DOM after its 250 ms
|
|
53
|
+
* slide-out, once the focus trap has restored its captured element. Holds
|
|
54
|
+
* on ×, Escape, backdrop, `open` false, and when the drawer is destroyed
|
|
55
|
+
* while open. A custom-element host that can't take focus (`<lc-button>`)
|
|
56
|
+
* hands it to its first focusable descendant. Ignored when the element is
|
|
57
|
+
* no longer in the document or can't take focus; the captured element then
|
|
58
|
+
* keeps it. `null`: as before.
|
|
59
|
+
* @default null
|
|
60
|
+
*/
|
|
61
|
+
readonly returnFocusTo: import("@angular/core").InputSignal<HTMLElement | null>;
|
|
45
62
|
/** Emitted when the drawer should close. */
|
|
46
63
|
readonly closed: import("@angular/core").OutputEmitterRef<void>;
|
|
47
64
|
/** Internal visibility — stays true during the slide-out animation. */
|
|
@@ -54,8 +71,22 @@ export declare class DrawerComponent implements OnDestroy {
|
|
|
54
71
|
private readonly drawerId;
|
|
55
72
|
private closeTimer?;
|
|
56
73
|
private originalOverflow?;
|
|
74
|
+
/**
|
|
75
|
+
* The environment injector: a node injector would cancel the focus-return
|
|
76
|
+
* hook when the drawer is destroyed while open.
|
|
77
|
+
*/
|
|
78
|
+
private readonly environmentInjector;
|
|
79
|
+
private destroyed;
|
|
57
80
|
constructor();
|
|
58
81
|
ngOnDestroy(): void;
|
|
82
|
+
/**
|
|
83
|
+
* Focuses `returnFocusTo` after the next render (3.35): the template
|
|
84
|
+
* refresh has removed the panel, and `cdkTrapFocus` has restored its
|
|
85
|
+
* captured element on destroy, so this is the last focus write. Reads the
|
|
86
|
+
* input again then, so a trigger re-rendered meanwhile is taken from a
|
|
87
|
+
* fresh query. Does nothing when the drawer opened again meanwhile.
|
|
88
|
+
*/
|
|
89
|
+
private scheduleFocusReturn;
|
|
59
90
|
/**
|
|
60
91
|
* Handle backdrop click. Ignored while another overlay (menu, popover, …)
|
|
61
92
|
* sits above this drawer — the click belongs to that layer.
|
|
@@ -118,6 +149,11 @@ export declare class DrawerComponent implements OnDestroy {
|
|
|
118
149
|
"required": false;
|
|
119
150
|
"isSignal": true;
|
|
120
151
|
};
|
|
152
|
+
"returnFocusTo": {
|
|
153
|
+
"alias": "returnFocusTo";
|
|
154
|
+
"required": false;
|
|
155
|
+
"isSignal": true;
|
|
156
|
+
};
|
|
121
157
|
}, {
|
|
122
158
|
"closed": "closed";
|
|
123
159
|
}, never, ["*"], true, never>;
|
|
@@ -23,7 +23,9 @@ export interface GalleryItem {
|
|
|
23
23
|
* - Configurable custom column count
|
|
24
24
|
* - Lightbox overlay with navigation (prev/next)
|
|
25
25
|
* - Keyboard navigation (Arrow keys, Escape); focus is trapped inside the
|
|
26
|
-
* lightbox and returned to the originating thumbnail on close
|
|
26
|
+
* lightbox and returned to the originating thumbnail on close: the clicked
|
|
27
|
+
* or tapped thumbnail, also in WebKit, where a tap doesn't focus it, so the
|
|
28
|
+
* gallery needs no `returnFocusTo` (3.35)
|
|
27
29
|
* - Optional captions and category filtering
|
|
28
30
|
* - Lazy loading with placeholder shimmer
|
|
29
31
|
* - Zoom control in lightbox
|