@lifecorner/angular-ui-kit 3.27.1 → 3.28.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.
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-chat.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/chat/chat.component.ts","../../../../libs/angular-ui-kit/src/lib/chat/chat.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n NgZone,\n TemplateRef,\n ContentChild,\n ViewChild,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { MarkdownComponent } from '@lifecorner/angular-ui-kit/markdown';\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} from '@lifecorner/angular-ui-kit/icons';\n\nexport type ChatMessageRole = 'user' | 'agent' | 'system';\n\n/**\n * Semantic status of a chat message — orthogonal to `role` (role = *who*\n * speaks; status = *what kind* of message). Reuses the semantic vocabulary of\n * `lc-alert` / `lc-callout` and drives the rail dot/accent colour + a status\n * icon. `'default'` (or omitted) reproduces the role-coloured behaviour exactly.\n */\nexport type ChatMessageStatus = 'default' | 'info' | 'success' | 'warning' | 'error';\n\n/**\n * Controls which messages are rendered as Markdown via `<lc-markdown>`.\n * - `false` (default): plain text rendering (legacy behavior)\n * - `true` / `'all'`: render every role as Markdown\n * - `'agent'`: only agent messages are rendered as Markdown (recommended)\n */\nexport type ChatRenderMarkdown = boolean | 'agent' | 'all';\n\n/**\n * Represents a file attached to a chat message or pending in the input.\n *\n * The `file` reference is only available for attachments produced by the\n * input (i.e. emitted via `messageSend` / `fileAttach`). Attachments\n * coming from the server or message history typically rely on `url` only.\n */\nexport interface ChatAttachment {\n id: string;\n name: string;\n /** MIME type, e.g. `image/png`, `application/pdf`. */\n type?: string;\n /** Size in bytes. */\n size?: number;\n /** Object URL or remote URL to preview / download the file. */\n url?: string;\n /** Raw browser File reference (set for newly uploaded files). */\n file?: File;\n}\n\nexport interface ChatMessage {\n id: string;\n role: ChatMessageRole;\n content: string;\n timestamp?: Date | string;\n avatar?: string;\n name?: string;\n streaming?: boolean;\n /**\n * Semantic status — colours the rail dot/accent and shows a status icon.\n * Independent of `role`: a `role: 'agent'` message can be `status: 'error'`\n * (failed reply) or `status: 'success'` (tool finished). Defaults to\n * `'default'`, which reproduces today's role-coloured behaviour exactly.\n * An `'error'` message never pulses and is announced assertively (`role=\"alert\"`).\n */\n status?: ChatMessageStatus;\n /** Optional file attachments associated with the message. */\n attachments?: ChatAttachment[];\n /** Arbitrary data passed to a custom messageTemplate. */\n data?: Record<string, unknown>;\n}\n\nexport interface ChatSendEvent {\n content: string;\n /** Files attached to the outgoing message, if any. */\n attachments?: ChatAttachment[];\n}\n\nexport interface ChatFileAttachEvent {\n attachments: ChatAttachment[];\n /** Files rejected because of `accept` / `maxFileSize` constraints. */\n rejected: { file: File; reason: 'type' | 'size' }[];\n}\n\n@Component({\n selector: 'lc-chat',\n standalone: true,\n imports: [NgTemplateOutlet, MarkdownComponent, IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_INFORMATION_CIRCLE, ICON_CHECK_CIRCLE, ICON_EXCLAMATION_TRIANGLE, ICON_CIRCLE_X])],\n templateUrl: './chat.component.html',\n styleUrls: ['./chat.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Chat component for conversational user interfaces.\n *\n * Compact, document-style layout: agent/system turns flow as full-width text on\n * a left timeline rail, while user turns render as right-aligned, accent-tinted\n * bubbles (no name label) with the timestamp on a muted line beneath. Spacing is\n * a single space-efficient scale (tunable via the `--lc-chat-*` custom\n * properties); there is no separate roomy variant.\n *\n * Features:\n * - User, agent, and system message roles\n * - Right-aligned user bubbles with an optional avatar: `msg.avatar` image, or a\n * monogram built from `msg.name` initials (gated by `showAvatars`)\n * - Agent/system turns on a left rail with a status dot, avatar or semantic icon\n * - Streaming cursor indicator for AI responses\n * - Typing indicator with animated dots\n * - Auto-scroll to the latest message (new turns, streamed tokens, history\n * loads) — only while the reader is at the bottom; scrolling up pauses it\n * - Optional avatars and timestamps\n * - Configurable header with title\n * - Send on Enter with Shift+Enter for newline\n * - Optional file upload (`allowFileUpload`) with `accept`/`maxFileSize`\n * constraints, preview chips, and image/file thumbnails inside messages.\n *\n * @example Basic\n * ```html\n * <lc-chat [messages]=\"messages\" title=\"Support\" (messageSend)=\"onSend($event)\" />\n * ```\n *\n * @example With file upload\n * ```html\n * <lc-chat\n * [messages]=\"messages\"\n * [allowFileUpload]=\"true\"\n * accept=\"image/*,.pdf\"\n * [maxFileSize]=\"5 * 1024 * 1024\"\n * (messageSend)=\"onSend($event)\"\n * (fileAttach)=\"onAttach($event)\" />\n * ```\n */\nexport class ChatComponent {\n private static nextId = 0;\n /** Id of the composer textarea (links the visually-hidden label). */\n protected readonly inputId = `lc-chat-input-${++ChatComponent.nextId}`;\n\n /** Messages to display. */\n messages = input<ChatMessage[]>([]);\n\n /** Placeholder text for the input. */\n placeholder = input<string>('Nachricht eingeben…');\n\n /** Accessible name of the composer textarea (visually hidden label). */\n inputLabel = input<string>('Nachricht');\n\n /** Title displayed in the header. */\n title = input<string>('Chat');\n\n /** Whether the agent is currently streaming / typing. */\n isStreaming = input<boolean>(false);\n\n /** Show the header bar. */\n showHeader = input<boolean>(true);\n\n /**\n * Draw the chat's own border + rounded corners. Defaults to `true` (card\n * style). Set `false` to render flush/edge-to-edge — e.g. when the chat is\n * the full-height body of an `<lc-page-layout>` and should sit directly under\n * a page header without a nested box.\n */\n bordered = input<boolean>(true);\n\n /**\n * Where messages stack when they don't fill the height.\n * - `'top'` (default): messages grow from the top down.\n * - `'bottom'`: messages anchor to the bottom (empty space above), like most\n * messaging apps. Still scrolls to reveal the top once they overflow.\n */\n messageAnchor = input<'top' | 'bottom'>('top');\n\n /**\n * Width of the message thread and composer.\n * - `'full'` (default): messages span the full available width.\n * - `'narrow'`: a centered, readable column (~46rem) like a document-style chat.\n */\n contentWidth = input<'narrow' | 'full'>('full');\n\n /** Disable the input. */\n disabled = input<boolean>(false);\n\n /** Show avatars next to messages. */\n showAvatars = input<boolean>(true);\n\n /** Show timestamps. */\n showTimestamps = input<boolean>(true);\n\n /**\n * Render message content as Markdown using `<lc-markdown variant=\"chat\">`.\n * Defaults to `'agent'` so agent replies get rich formatting while user\n * input stays as plain text. Pass `false` to opt out, or `true`/`'all'`\n * to render every role as Markdown.\n */\n renderMarkdown = input<ChatRenderMarkdown>('agent');\n\n /** Enable the file-upload (paperclip) button in the input area. */\n allowFileUpload = input<boolean>(false);\n\n /**\n * Comma-separated list of accepted file types, forwarded to the native\n * `<input accept>` attribute. Examples: `image/*`, `.pdf,.docx`.\n */\n accept = input<string>('');\n\n /** Allow selecting multiple files at once. Defaults to `true`. */\n multiple = input<boolean>(true);\n\n /** Maximum file size in bytes. `0` disables the check. */\n maxFileSize = input<number>(0);\n\n /** BCP 47 locale of the message times (hour and minute). */\n locale = input('de-DE');\n\n /** Header badge while a message is streaming. */\n streamingLabel = input('Streaming…');\n\n /** Accessible name of the attach button (`allowFileUpload`). */\n attachAriaLabel = input('Datei anhängen');\n\n /** Accessible name of the send button. */\n sendAriaLabel = input('Send');\n\n /** Screen-reader prefix of messages with status `info`. */\n statusInfoLabel = input('Info:');\n\n /** Screen-reader prefix of messages with status `success`. */\n statusSuccessLabel = input('Erfolg:');\n\n /** Screen-reader prefix of messages with status `warning`. */\n statusWarningLabel = input('Warnung:');\n\n /** Screen-reader prefix of messages with status `error`. */\n statusErrorLabel = input('Fehler:');\n\n /** Accessible name prefix of a pending attachment's remove button, followed by the file name. */\n removeAttachmentAriaLabel = input('Entfernen:');\n\n /** Emits when user sends a message. */\n messageSend = output<ChatSendEvent>();\n\n /** Emits whenever files are added to the pending attachments list. */\n fileAttach = output<ChatFileAttachEvent>();\n\n /** Custom template for rendering message content. Context: { $implicit: ChatMessage } */\n @ContentChild('messageTemplate') messageTemplate?: TemplateRef<{ $implicit: ChatMessage }>;\n\n protected readonly inputValue = signal('');\n protected readonly pendingAttachments = signal<ChatAttachment[]>([]);\n private attachmentCounter = 0;\n\n private readonly injector = inject(Injector);\n private readonly destroyRef = inject(DestroyRef);\n private readonly ngZone = inject(NgZone);\n\n /**\n * Whether the reader is (near) the bottom of the thread. Auto-scroll only\n * follows new content while this is true, so scrolling up to re-read is\n * never fought. Plain field: updated from a passive scroll listener outside\n * the zone, read untracked by the follow effect.\n */\n private atBottom = true;\n\n /** Distance from the bottom (px) still counted as \"at the bottom\". */\n private static readonly AT_BOTTOM_THRESHOLD = 32;\n\n private readonly scrollContainer = viewChild.required<ElementRef<HTMLDivElement>>('scrollContainer');\n @ViewChild('fileInput') private fileInput?: ElementRef<HTMLInputElement>;\n @ViewChild('composerInput') private composerInput?: ElementRef<HTMLTextAreaElement>;\n\n /** Upper bound for the auto-growing composer before it starts scrolling (px). */\n private static readonly INPUT_MAX_HEIGHT = 192;\n\n protected readonly formattedMessages = computed(() =>\n this.messages().map(m => ({\n ...m,\n timestamp: m.timestamp instanceof Date ? m.timestamp : m.timestamp ? new Date(m.timestamp) : undefined,\n }))\n );\n\n /**\n * Text for the visually-hidden live region: the most recent *completed*\n * non-user message. Streaming turns are announced once they finish (a\n * token-by-token live region would be unusable); user turns were typed by\n * the reader; semantic-status messages carry their own `aria-live`/`alert`.\n */\n protected readonly announcement = computed(() => {\n const msgs = this.messages();\n for (let i = msgs.length - 1; i >= 0; i--) {\n const m = msgs[i];\n if (m.role === 'user' || m.streaming || this.isSemanticStatus(m.status)) continue;\n return m.name ? `${m.name}: ${m.content}` : m.content;\n }\n return '';\n });\n\n constructor() {\n // Passive scroll tracking outside the zone — no CD per scroll frame.\n afterNextRender(() => {\n const el = this.scrollContainer().nativeElement;\n const onScroll = () => {\n this.atBottom =\n el.scrollHeight - el.scrollTop - el.clientHeight < ChatComponent.AT_BOTTOM_THRESHOLD;\n };\n this.ngZone.runOutsideAngular(() => el.addEventListener('scroll', onScroll, { passive: true }));\n this.destroyRef.onDestroy(() => el.removeEventListener('scroll', onScroll));\n });\n\n // Follow the conversation: a new turn, a streamed token on the last turn\n // (the parent hands in a new `messages` array), a history load or the\n // typing indicator appearing all grow the thread — scroll after render,\n // but only if the reader was already at the bottom.\n effect(() => {\n this.messages();\n this.isStreaming();\n if (!this.atBottom) return;\n afterNextRender(() => this.scrollToBottom(), { injector: this.injector });\n });\n }\n\n protected onInput(event: Event): void {\n const el = event.target as HTMLTextAreaElement;\n this.inputValue.set(el.value);\n this.autoGrow(el);\n }\n\n /** Resize the textarea to fit its content so the composer hugs the text. */\n private autoGrow(el: HTMLTextAreaElement): void {\n el.style.height = 'auto';\n el.style.height = `${Math.min(el.scrollHeight, ChatComponent.INPUT_MAX_HEIGHT)}px`;\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n // Enter while an IME composition is open commits the composition, not the message.\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.send();\n }\n }\n\n protected send(): void {\n const content = this.inputValue().trim();\n const attachments = this.pendingAttachments();\n if ((!content && attachments.length === 0) || this.disabled()) return;\n this.messageSend.emit({\n content,\n attachments: attachments.length ? attachments : undefined,\n });\n this.inputValue.set('');\n this.pendingAttachments.set([]);\n // Sending re-engages follow mode: the reader wants to see their own turn\n // and the reply, even if they had scrolled up before.\n this.atBottom = true;\n afterNextRender(() => this.scrollToBottom(), { injector: this.injector });\n // Collapse the auto-grown textarea back to a single row.\n const el = this.composerInput?.nativeElement;\n if (el) el.style.height = 'auto';\n }\n\n protected openFilePicker(): void {\n if (this.disabled() || !this.allowFileUpload()) return;\n this.fileInput?.nativeElement.click();\n }\n\n protected onFilesSelected(event: Event): void {\n const input = event.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n this.addFiles(Array.from(input.files));\n // Reset so the same file can be re-selected later.\n input.value = '';\n }\n\n protected removeAttachment(id: string): void {\n this.pendingAttachments.update(list => {\n const removed = list.find(a => a.id === id);\n if (removed?.url && removed.file) {\n URL.revokeObjectURL(removed.url);\n }\n return list.filter(a => a.id !== id);\n });\n }\n\n protected formatBytes(size: number | undefined): string {\n if (!size && size !== 0) return '';\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;\n return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n }\n\n protected isImage(att: ChatAttachment): boolean {\n return !!att.type?.startsWith('image/');\n }\n\n private addFiles(files: File[]): void {\n const max = this.maxFileSize();\n const acceptList = this.accept()\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n const accepted: ChatAttachment[] = [];\n const rejected: { file: File; reason: 'type' | 'size' }[] = [];\n\n for (const file of files) {\n if (max > 0 && file.size > max) {\n rejected.push({ file, reason: 'size' });\n continue;\n }\n if (acceptList.length > 0 && !this.matchesAccept(file, acceptList)) {\n rejected.push({ file, reason: 'type' });\n continue;\n }\n accepted.push({\n id: `att-${Date.now()}-${this.attachmentCounter++}`,\n name: file.name,\n type: file.type,\n size: file.size,\n url: URL.createObjectURL(file),\n file,\n });\n }\n\n if (accepted.length) {\n this.pendingAttachments.update(list => [...list, ...accepted]);\n }\n if (accepted.length || rejected.length) {\n this.fileAttach.emit({ attachments: accepted, rejected });\n }\n }\n\n private matchesAccept(file: File, acceptList: string[]): boolean {\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return acceptList.some(rule => {\n const r = rule.toLowerCase();\n if (r.startsWith('.')) return name.endsWith(r);\n if (r.endsWith('/*')) return type.startsWith(r.slice(0, -1));\n return type === r;\n });\n }\n\n protected formatTime(date: Date | undefined): string {\n if (!date) return '';\n return date.toLocaleTimeString(this.locale(), { hour: '2-digit', minute: '2-digit' });\n }\n\n /**\n * Up to two uppercase initials from a name (first + last word), used for the\n * user avatar monogram when no `avatar` image is provided. Returns `''` for an\n * empty/whitespace name so the caller can skip rendering.\n */\n protected initials(name: string | undefined): string {\n if (!name) return '';\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return '';\n const first = parts[0][0] ?? '';\n const last = parts.length > 1 ? parts[parts.length - 1][0] ?? '' : '';\n return (first + last).toUpperCase();\n }\n\n /**\n * Whether to show an avatar on a user turn: only when avatars are enabled and\n * the message carries either an image or a name we can build a monogram from.\n * Keeps the labelless bubble clean when there's nothing to show.\n */\n protected showUserAvatar(msg: ChatMessage): boolean {\n return (\n msg.role === 'user' &&\n this.showAvatars() &&\n !!(msg.avatar || this.initials(msg.name))\n );\n }\n\n protected shouldRenderMarkdown(role: ChatMessageRole): boolean {\n const mode = this.renderMarkdown();\n if (mode === false) return false;\n if (mode === true || mode === 'all') return true;\n return role === mode;\n }\n\n /** Whether a message carries a semantic (non-`default`) status. */\n protected isSemanticStatus(status: ChatMessageStatus | undefined): boolean {\n return !!status && status !== 'default';\n }\n\n /** Rail icon for a semantic status — reuses the `lc-alert` icon names. */\n protected statusIcon(status: ChatMessageStatus | undefined): string {\n switch (status) {\n case 'info':\n return 'information-circle';\n case 'success':\n return 'check-circle';\n case 'warning':\n return 'exclamation-triangle';\n case 'error':\n return 'x-circle';\n default:\n return '';\n }\n }\n\n /** Semantic token colour for a status dot/icon. */\n protected statusColor(status: ChatMessageStatus | undefined): string {\n switch (status) {\n case 'info':\n return 'var(--color-info-500)';\n case 'success':\n return 'var(--color-success-500)';\n case 'warning':\n return 'var(--color-warning-500)';\n case 'error':\n return 'var(--color-error-500)';\n default:\n return 'currentColor';\n }\n }\n\n /** Visually-hidden prefix so colour/icon is never the only signal. */\n protected statusLabel(status: ChatMessageStatus | undefined): string {\n switch (status) {\n case 'info':\n return this.statusInfoLabel();\n case 'success':\n return this.statusSuccessLabel();\n case 'warning':\n return this.statusWarningLabel();\n case 'error':\n return this.statusErrorLabel();\n default:\n return '';\n }\n }\n\n /** ARIA live priority: assertive for `error`, polite for other statuses. */\n protected statusAriaLive(status: ChatMessageStatus | undefined): 'assertive' | 'polite' | null {\n if (status === 'error') return 'assertive';\n if (this.isSemanticStatus(status)) return 'polite';\n return null;\n }\n\n private scrollToBottom(): void {\n const el = this.scrollContainer().nativeElement;\n el.scrollTop = el.scrollHeight;\n }\n}\n","<div\n class=\"lc-chat\"\n [class.lc-chat--borderless]=\"!bordered()\"\n [class.lc-chat--width-narrow]=\"contentWidth() === 'narrow'\"\n [class.lc-chat--width-full]=\"contentWidth() === 'full'\"\n>\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">{{ streamingLabel() }}</span>\n }\n </div>\n }\n\n <div\n class=\"lc-chat__messages\"\n [class.lc-chat__messages--anchor-bottom]=\"messageAnchor() === 'bottom'\"\n #scrollContainer\n >\n <div class=\"lc-chat__thread\">\n @for (msg of formattedMessages(); track msg.id) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n [class.lc-chat__message--avatar]=\"showUserAvatar(msg)\"\n [class.lc-chat__message--streaming]=\"msg.streaming\"\n [attr.role]=\"msg.status === 'error' ? 'alert' : null\"\n [attr.aria-live]=\"statusAriaLive(msg.status)\"\n >\n @if ((msg.role !== 'user' && (showAvatars() || isSemanticStatus(msg.status))) || showUserAvatar(msg)) {\n <div class=\"lc-chat__marker\" [class.lc-chat__marker--user]=\"msg.role === 'user'\">\n @if (isSemanticStatus(msg.status) && msg.role !== 'user') {\n <span class=\"lc-chat__status-icon\">\n <lc-icon [name]=\"statusIcon(msg.status)\" size=\"xs\" [color]=\"statusColor(msg.status)\" [decorative]=\"true\" />\n </span>\n } @else if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else if (msg.role === 'user') {\n <span class=\"lc-chat__monogram\" [attr.aria-label]=\"msg.name\">{{ initials(msg.name) }}</span>\n } @else {\n <span\n class=\"lc-chat__dot\"\n [class.lc-chat__dot--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__dot--system]=\"msg.role === 'system'\"\n ></span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__meta lc-chat__meta--agent\">\n <span class=\"lc-chat__name\">{{ msg.name }}</span>\n <span class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</span>\n </div>\n } @else {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n }\n <div class=\"lc-chat__content\">\n @if (isSemanticStatus(msg.status)) {\n <span class=\"lc-chat__sr-only\">{{ statusLabel(msg.status) }} </span>\n }\n @if (messageTemplate) {\n <ng-container *ngTemplateOutlet=\"messageTemplate; context: { $implicit: msg }\" />\n } @else if (shouldRenderMarkdown(msg.role)) {\n <lc-markdown [content]=\"msg.content\" variant=\"chat\" />\n } @else {\n {{ msg.content }}\n }\n <span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span>\n </div>\n @if (msg.attachments?.length) {\n <div class=\"lc-chat__attachments\">\n @for (att of msg.attachments; track att.id) {\n @if (isImage(att) && att.url) {\n <a class=\"lc-chat__attachment lc-chat__attachment--image\" [href]=\"att.url\" target=\"_blank\" rel=\"noopener\">\n <img [src]=\"att.url\" [alt]=\"att.name\" />\n </a>\n } @else {\n <a\n class=\"lc-chat__attachment lc-chat__attachment--file\"\n [href]=\"att.url || null\"\n [attr.download]=\"att.url ? att.name : null\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"lc-chat__attachment-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__attachment-size\">{{ formatBytes(att.size) }}</span>\n }\n </a>\n }\n }\n </div>\n }\n @if (showTimestamps() && msg.timestamp && msg.role !== 'user' && !msg.name) {\n <div class=\"lc-chat__time lc-chat__time--tight\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n @if (showTimestamps() && msg.timestamp && msg.role === 'user') {\n <div class=\"lc-chat__time lc-chat__time--user\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__marker\">\n <span class=\"lc-chat__dot lc-chat__dot--agent\"></span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Announces the latest completed non-user turn (see `announcement`). -->\n <div class=\"lc-chat__sr-only lc-chat__announcer\" aria-live=\"polite\" aria-atomic=\"true\">{{ announcement() }}</div>\n\n <div class=\"lc-chat__input-area\">\n <div class=\"lc-chat__composer\">\n @if (allowFileUpload() && pendingAttachments().length) {\n <div class=\"lc-chat__pending-attachments\">\n @for (att of pendingAttachments(); track att.id) {\n <div class=\"lc-chat__pending-attachment\" [class.lc-chat__pending-attachment--image]=\"isImage(att)\">\n @if (isImage(att) && att.url) {\n <img class=\"lc-chat__pending-thumb\" [src]=\"att.url\" [alt]=\"att.name\" />\n } @else {\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n }\n <span class=\"lc-chat__pending-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__pending-size\">{{ formatBytes(att.size) }}</span>\n }\n <button\n type=\"button\"\n class=\"lc-chat__pending-remove\"\n (click)=\"removeAttachment(att.id)\"\n [attr.aria-label]=\"removeAttachmentAriaLabel() + ' ' + att.name\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n }\n\n <label class=\"lc-chat__sr-only\" [for]=\"inputId\">{{ inputLabel() }}</label>\n <textarea\n #composerInput\n [id]=\"inputId\"\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n\n <div class=\"lc-chat__composer-actions\">\n @if (allowFileUpload()) {\n <input\n #fileInput\n type=\"file\"\n class=\"lc-chat__file-input\"\n [accept]=\"accept() || null\"\n [multiple]=\"multiple()\"\n (change)=\"onFilesSelected($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-chat__attach-btn\"\n [disabled]=\"disabled()\"\n (click)=\"openFilePicker()\"\n [attr.aria-label]=\"attachAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M14.5 9.5l-5 5a3 3 0 0 1-4.243-4.243l6.364-6.364a2 2 0 0 1 2.829 2.829l-6.364 6.364a1 1 0 1 1-1.415-1.415L11.5 6.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n }\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"(!inputValue().trim() && !pendingAttachments().length) || disabled()\"\n (click)=\"send()\"\n [attr.aria-label]=\"sendAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-chat.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/chat/chat.component.ts","../../../../libs/angular-ui-kit/src/lib/chat/chat.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n Injector,\n NgZone,\n TemplateRef,\n ContentChild,\n ViewChild,\n afterNextRender,\n computed,\n effect,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { NgTemplateOutlet } from '@angular/common';\nimport { MarkdownComponent } from '@lifecorner/angular-ui-kit/markdown';\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} from '@lifecorner/angular-ui-kit/icons';\n\nexport type ChatMessageRole = 'user' | 'agent' | 'system';\n\n/**\n * Semantic status of a chat message — orthogonal to `role` (role = *who*\n * speaks; status = *what kind* of message). Reuses the semantic vocabulary of\n * `lc-alert` / `lc-callout` and drives the rail dot/accent colour + a status\n * icon. `'default'` (or omitted) reproduces the role-coloured behaviour exactly.\n */\nexport type ChatMessageStatus = 'default' | 'info' | 'success' | 'warning' | 'error';\n\n/**\n * Controls which messages are rendered as Markdown via `<lc-markdown>`.\n * - `false` (default): plain text rendering (legacy behavior)\n * - `true` / `'all'`: render every role as Markdown\n * - `'agent'`: only agent messages are rendered as Markdown (recommended)\n */\nexport type ChatRenderMarkdown = boolean | 'agent' | 'all';\n\n/**\n * Represents a file attached to a chat message or pending in the input.\n *\n * The `file` reference is only available for attachments produced by the\n * input (i.e. emitted via `messageSend` / `fileAttach`). Attachments\n * coming from the server or message history typically rely on `url` only.\n */\nexport interface ChatAttachment {\n id: string;\n name: string;\n /** MIME type, e.g. `image/png`, `application/pdf`. */\n type?: string;\n /** Size in bytes. */\n size?: number;\n /** Object URL or remote URL to preview / download the file. */\n url?: string;\n /** Raw browser File reference (set for newly uploaded files). */\n file?: File;\n}\n\nexport interface ChatMessage {\n id: string;\n role: ChatMessageRole;\n content: string;\n timestamp?: Date | string;\n avatar?: string;\n name?: string;\n streaming?: boolean;\n /**\n * Semantic status — colours the rail dot/accent and shows a status icon.\n * Independent of `role`: a `role: 'agent'` message can be `status: 'error'`\n * (failed reply) or `status: 'success'` (tool finished). Defaults to\n * `'default'`, which reproduces today's role-coloured behaviour exactly.\n * An `'error'` message never pulses and is announced assertively (`role=\"alert\"`).\n */\n status?: ChatMessageStatus;\n /** Optional file attachments associated with the message. */\n attachments?: ChatAttachment[];\n /** Arbitrary data passed to a custom messageTemplate. */\n data?: Record<string, unknown>;\n}\n\nexport interface ChatSendEvent {\n content: string;\n /** Files attached to the outgoing message, if any. */\n attachments?: ChatAttachment[];\n}\n\nexport interface ChatFileAttachEvent {\n attachments: ChatAttachment[];\n /** Files rejected because of `accept` / `maxFileSize` constraints. */\n rejected: { file: File; reason: 'type' | 'size' }[];\n}\n\n@Component({\n selector: 'lc-chat',\n standalone: true,\n imports: [NgTemplateOutlet, MarkdownComponent, IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_INFORMATION_CIRCLE, ICON_CHECK_CIRCLE, ICON_EXCLAMATION_TRIANGLE, ICON_CIRCLE_X])],\n templateUrl: './chat.component.html',\n styleUrls: ['./chat.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\n/**\n * Chat component for conversational user interfaces.\n *\n * Compact, document-style layout: agent/system turns flow as full-width text on\n * a left timeline rail, while user turns render as right-aligned, accent-tinted\n * bubbles (no name label) with the timestamp on a muted line beneath. Spacing is\n * a single space-efficient scale (tunable via the `--lc-chat-*` custom\n * properties); there is no separate roomy variant.\n *\n * Features:\n * - User, agent, and system message roles\n * - Right-aligned user bubbles with an optional avatar: `msg.avatar` image, or a\n * monogram built from `msg.name` initials (gated by `showAvatars`)\n * - Agent/system turns on a left rail with a status dot, avatar or semantic icon\n * - Streaming cursor indicator for AI responses\n * - Typing indicator with animated dots\n * - Auto-scroll to the latest message (new turns, streamed tokens, history\n * loads) — only while the reader is at the bottom; scrolling up pauses it\n * - Optional avatars and timestamps\n * - Configurable header with title\n * - Send on Enter with Shift+Enter for newline\n * - Optional file upload (`allowFileUpload`) with `accept`/`maxFileSize`\n * constraints, preview chips, and image/file thumbnails inside messages.\n *\n * @example Basic\n * ```html\n * <lc-chat [messages]=\"messages\" title=\"Support\" (messageSend)=\"onSend($event)\" />\n * ```\n *\n * @example With file upload\n * ```html\n * <lc-chat\n * [messages]=\"messages\"\n * [allowFileUpload]=\"true\"\n * accept=\"image/*,.pdf\"\n * [maxFileSize]=\"5 * 1024 * 1024\"\n * (messageSend)=\"onSend($event)\"\n * (fileAttach)=\"onAttach($event)\" />\n * ```\n */\nexport class ChatComponent {\n private static nextId = 0;\n /** Id of the composer textarea (links the visually-hidden label). */\n protected readonly inputId = `lc-chat-input-${++ChatComponent.nextId}`;\n\n /** Messages to display. */\n messages = input<ChatMessage[]>([]);\n\n /** Placeholder text for the input. */\n placeholder = input<string>('Nachricht eingeben…');\n\n /** Accessible name of the composer textarea (visually hidden label). */\n inputLabel = input<string>('Nachricht');\n\n /** Title displayed in the header. */\n title = input<string>('Chat');\n\n /** Whether the agent is currently streaming / typing. */\n isStreaming = input<boolean>(false);\n\n /** Show the header bar. */\n showHeader = input<boolean>(true);\n\n /**\n * Draw the chat's own border + rounded corners. Defaults to `true` (card\n * style). Set `false` to render flush/edge-to-edge — e.g. when the chat is\n * the full-height body of an `<lc-page-layout>` and should sit directly under\n * a page header without a nested box.\n */\n bordered = input<boolean>(true);\n\n /**\n * Where messages stack when they don't fill the height.\n * - `'top'` (default): messages grow from the top down.\n * - `'bottom'`: messages anchor to the bottom (empty space above), like most\n * messaging apps. Still scrolls to reveal the top once they overflow.\n */\n messageAnchor = input<'top' | 'bottom'>('top');\n\n /**\n * Width of the message thread and composer.\n * - `'full'` (default): messages span the full available width.\n * - `'narrow'`: a centered, readable column (~46rem) like a document-style chat.\n */\n contentWidth = input<'narrow' | 'full'>('full');\n\n /** Disable the input. */\n disabled = input<boolean>(false);\n\n /** Show avatars next to messages. */\n showAvatars = input<boolean>(true);\n\n /** Show timestamps. */\n showTimestamps = input<boolean>(true);\n\n /**\n * Render message content as Markdown using `<lc-markdown variant=\"chat\">`.\n * Defaults to `'agent'` so agent replies get rich formatting while user\n * input stays as plain text. Pass `false` to opt out, or `true`/`'all'`\n * to render every role as Markdown.\n */\n renderMarkdown = input<ChatRenderMarkdown>('agent');\n\n /** Enable the file-upload (paperclip) button in the input area. */\n allowFileUpload = input<boolean>(false);\n\n /**\n * Comma-separated list of accepted file types, forwarded to the native\n * `<input accept>` attribute. Examples: `image/*`, `.pdf,.docx`.\n */\n accept = input<string>('');\n\n /** Allow selecting multiple files at once. Defaults to `true`. */\n multiple = input<boolean>(true);\n\n /** Maximum file size in bytes. `0` disables the check. */\n maxFileSize = input<number>(0);\n\n /** BCP 47 locale of the message times (hour and minute). */\n locale = input('de-DE');\n\n /** Header badge while a message is streaming. */\n streamingLabel = input('Streaming…');\n\n /** Accessible name of the attach button (`allowFileUpload`). */\n attachAriaLabel = input('Datei anhängen');\n\n /** Accessible name of the send button. */\n sendAriaLabel = input('Send');\n\n /** Screen-reader prefix of messages with status `info`. */\n statusInfoLabel = input('Info:');\n\n /** Screen-reader prefix of messages with status `success`. */\n statusSuccessLabel = input('Erfolg:');\n\n /** Screen-reader prefix of messages with status `warning`. */\n statusWarningLabel = input('Warnung:');\n\n /** Screen-reader prefix of messages with status `error`. */\n statusErrorLabel = input('Fehler:');\n\n /** Accessible name prefix of a pending attachment's remove button, followed by the file name. */\n removeAttachmentAriaLabel = input('Entfernen:');\n\n /** Emits when user sends a message. */\n messageSend = output<ChatSendEvent>();\n\n /** Emits whenever files are added to the pending attachments list. */\n fileAttach = output<ChatFileAttachEvent>();\n\n /** Custom template for rendering message content. Context: { $implicit: ChatMessage } */\n @ContentChild('messageTemplate') messageTemplate?: TemplateRef<{ $implicit: ChatMessage }>;\n\n protected readonly inputValue = signal('');\n protected readonly pendingAttachments = signal<ChatAttachment[]>([]);\n private attachmentCounter = 0;\n\n private readonly injector = inject(Injector);\n private readonly destroyRef = inject(DestroyRef);\n private readonly ngZone = inject(NgZone);\n\n /**\n * Whether the reader is (near) the bottom of the thread. Auto-scroll only\n * follows new content while this is true, so scrolling up to re-read is\n * never fought. Plain field: updated from a passive scroll listener outside\n * the zone, read untracked by the follow effect.\n */\n private atBottom = true;\n\n /** Distance from the bottom (px) still counted as \"at the bottom\". */\n private static readonly AT_BOTTOM_THRESHOLD = 32;\n\n private readonly scrollContainer = viewChild.required<ElementRef<HTMLDivElement>>('scrollContainer');\n @ViewChild('fileInput') private fileInput?: ElementRef<HTMLInputElement>;\n @ViewChild('composerInput') private composerInput?: ElementRef<HTMLTextAreaElement>;\n\n /** Upper bound for the auto-growing composer before it starts scrolling (px). */\n private static readonly INPUT_MAX_HEIGHT = 192;\n\n protected readonly formattedMessages = computed(() =>\n this.messages().map(m => ({\n ...m,\n timestamp: m.timestamp instanceof Date ? m.timestamp : m.timestamp ? new Date(m.timestamp) : undefined,\n }))\n );\n\n /**\n * Text for the visually-hidden live region: the most recent *completed*\n * non-user message. Streaming turns are announced once they finish (a\n * token-by-token live region would be unusable); user turns were typed by\n * the reader; semantic-status messages carry their own `aria-live`/`alert`.\n */\n protected readonly announcement = computed(() => {\n const msgs = this.messages();\n for (let i = msgs.length - 1; i >= 0; i--) {\n const m = msgs[i];\n if (m.role === 'user' || m.streaming || this.isSemanticStatus(m.status)) continue;\n return m.name ? `${m.name}: ${m.content}` : m.content;\n }\n return '';\n });\n\n constructor() {\n // Passive scroll tracking outside the zone — no CD per scroll frame.\n afterNextRender(() => {\n const el = this.scrollContainer().nativeElement;\n const onScroll = () => {\n this.atBottom =\n el.scrollHeight - el.scrollTop - el.clientHeight < ChatComponent.AT_BOTTOM_THRESHOLD;\n };\n this.ngZone.runOutsideAngular(() => el.addEventListener('scroll', onScroll, { passive: true }));\n this.destroyRef.onDestroy(() => el.removeEventListener('scroll', onScroll));\n });\n\n // Follow the conversation: a new turn, a streamed token on the last turn\n // (the parent hands in a new `messages` array), a history load or the\n // typing indicator appearing all grow the thread — scroll after render,\n // but only if the reader was already at the bottom.\n effect(() => {\n this.messages();\n this.isStreaming();\n if (!this.atBottom) return;\n afterNextRender(() => this.scrollToBottom(), { injector: this.injector });\n });\n }\n\n protected onInput(event: Event): void {\n const el = event.target as HTMLTextAreaElement;\n this.inputValue.set(el.value);\n this.autoGrow(el);\n }\n\n /** Resize the textarea to fit its content so the composer hugs the text. */\n private autoGrow(el: HTMLTextAreaElement): void {\n el.style.height = 'auto';\n el.style.height = `${Math.min(el.scrollHeight, ChatComponent.INPUT_MAX_HEIGHT)}px`;\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n // Enter while an IME composition is open commits the composition, not the message.\n if (event.key === 'Enter' && !event.shiftKey && !event.isComposing) {\n event.preventDefault();\n this.send();\n }\n }\n\n protected send(): void {\n const content = this.inputValue().trim();\n const attachments = this.pendingAttachments();\n if ((!content && attachments.length === 0) || this.disabled()) return;\n this.messageSend.emit({\n content,\n attachments: attachments.length ? attachments : undefined,\n });\n this.inputValue.set('');\n this.pendingAttachments.set([]);\n // Sending re-engages follow mode: the reader wants to see their own turn\n // and the reply, even if they had scrolled up before.\n this.atBottom = true;\n afterNextRender(() => this.scrollToBottom(), { injector: this.injector });\n // Collapse the auto-grown textarea back to a single row.\n const el = this.composerInput?.nativeElement;\n if (el) el.style.height = 'auto';\n }\n\n protected openFilePicker(): void {\n if (this.disabled() || !this.allowFileUpload()) return;\n this.fileInput?.nativeElement.click();\n }\n\n protected onFilesSelected(event: Event): void {\n const input = event.target as HTMLInputElement;\n if (!input.files || input.files.length === 0) return;\n this.addFiles(Array.from(input.files));\n // Reset so the same file can be re-selected later.\n input.value = '';\n }\n\n protected removeAttachment(id: string): void {\n this.pendingAttachments.update(list => {\n const removed = list.find(a => a.id === id);\n if (removed?.url && removed.file) {\n URL.revokeObjectURL(removed.url);\n }\n return list.filter(a => a.id !== id);\n });\n }\n\n protected formatBytes(size: number | undefined): string {\n if (!size && size !== 0) return '';\n if (size < 1024) return `${size} B`;\n if (size < 1024 * 1024) return `${(size / 1024).toFixed(1)} KB`;\n return `${(size / (1024 * 1024)).toFixed(1)} MB`;\n }\n\n protected isImage(att: ChatAttachment): boolean {\n return !!att.type?.startsWith('image/');\n }\n\n private addFiles(files: File[]): void {\n const max = this.maxFileSize();\n const acceptList = this.accept()\n .split(',')\n .map(s => s.trim())\n .filter(Boolean);\n\n const accepted: ChatAttachment[] = [];\n const rejected: { file: File; reason: 'type' | 'size' }[] = [];\n\n for (const file of files) {\n if (max > 0 && file.size > max) {\n rejected.push({ file, reason: 'size' });\n continue;\n }\n if (acceptList.length > 0 && !this.matchesAccept(file, acceptList)) {\n rejected.push({ file, reason: 'type' });\n continue;\n }\n accepted.push({\n id: `att-${Date.now()}-${this.attachmentCounter++}`,\n name: file.name,\n type: file.type,\n size: file.size,\n url: URL.createObjectURL(file),\n file,\n });\n }\n\n if (accepted.length) {\n this.pendingAttachments.update(list => [...list, ...accepted]);\n }\n if (accepted.length || rejected.length) {\n this.fileAttach.emit({ attachments: accepted, rejected });\n }\n }\n\n private matchesAccept(file: File, acceptList: string[]): boolean {\n const name = file.name.toLowerCase();\n const type = file.type.toLowerCase();\n return acceptList.some(rule => {\n const r = rule.toLowerCase();\n if (r.startsWith('.')) return name.endsWith(r);\n if (r.endsWith('/*')) return type.startsWith(r.slice(0, -1));\n return type === r;\n });\n }\n\n protected formatTime(date: Date | undefined): string {\n if (!date) return '';\n return date.toLocaleTimeString(this.locale(), { hour: '2-digit', minute: '2-digit' });\n }\n\n /**\n * Up to two uppercase initials from a name (first + last word), used for the\n * user avatar monogram when no `avatar` image is provided. Returns `''` for an\n * empty/whitespace name so the caller can skip rendering.\n */\n protected initials(name: string | undefined): string {\n if (!name) return '';\n const parts = name.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return '';\n const first = parts[0][0] ?? '';\n const last = parts.length > 1 ? parts[parts.length - 1][0] ?? '' : '';\n return (first + last).toUpperCase();\n }\n\n /**\n * Whether to show an avatar on a user turn: only when avatars are enabled and\n * the message carries either an image or a name we can build a monogram from.\n * Keeps the labelless bubble clean when there's nothing to show.\n */\n protected showUserAvatar(msg: ChatMessage): boolean {\n return (\n msg.role === 'user' &&\n this.showAvatars() &&\n !!(msg.avatar || this.initials(msg.name))\n );\n }\n\n protected shouldRenderMarkdown(role: ChatMessageRole): boolean {\n const mode = this.renderMarkdown();\n if (mode === false) return false;\n if (mode === true || mode === 'all') return true;\n return role === mode;\n }\n\n /** Whether a message carries a semantic (non-`default`) status. */\n protected isSemanticStatus(status: ChatMessageStatus | undefined): boolean {\n return !!status && status !== 'default';\n }\n\n /** Rail icon for a semantic status — reuses the `lc-alert` icon names. */\n protected statusIcon(status: ChatMessageStatus | undefined): string {\n switch (status) {\n case 'info':\n return 'information-circle';\n case 'success':\n return 'check-circle';\n case 'warning':\n return 'exclamation-triangle';\n case 'error':\n return 'x-circle';\n default:\n return '';\n }\n }\n\n /** Semantic token colour for a status dot/icon. */\n protected statusColor(status: ChatMessageStatus | undefined): string {\n switch (status) {\n case 'info':\n return 'var(--color-info-500)';\n case 'success':\n return 'var(--color-success-500)';\n case 'warning':\n return 'var(--color-warning-500)';\n case 'error':\n return 'var(--color-error-500)';\n default:\n return 'currentColor';\n }\n }\n\n /** Visually-hidden prefix so colour/icon is never the only signal. */\n protected statusLabel(status: ChatMessageStatus | undefined): string {\n switch (status) {\n case 'info':\n return this.statusInfoLabel();\n case 'success':\n return this.statusSuccessLabel();\n case 'warning':\n return this.statusWarningLabel();\n case 'error':\n return this.statusErrorLabel();\n default:\n return '';\n }\n }\n\n /** ARIA live priority: assertive for `error`, polite for other statuses. */\n protected statusAriaLive(status: ChatMessageStatus | undefined): 'assertive' | 'polite' | null {\n if (status === 'error') return 'assertive';\n if (this.isSemanticStatus(status)) return 'polite';\n return null;\n }\n\n private scrollToBottom(): void {\n const el = this.scrollContainer().nativeElement;\n el.scrollTop = el.scrollHeight;\n }\n}\n","<div\n class=\"lc-chat\"\n [class.lc-chat--borderless]=\"!bordered()\"\n [class.lc-chat--width-narrow]=\"contentWidth() === 'narrow'\"\n [class.lc-chat--width-full]=\"contentWidth() === 'full'\"\n>\n @if (showHeader()) {\n <div class=\"lc-chat__header\">\n <span class=\"lc-chat__title\">{{ title() }}</span>\n @if (isStreaming()) {\n <span class=\"lc-chat__streaming-badge\">{{ streamingLabel() }}</span>\n }\n </div>\n }\n\n <div\n class=\"lc-chat__messages\"\n [class.lc-chat__messages--anchor-bottom]=\"messageAnchor() === 'bottom'\"\n #scrollContainer\n >\n <div class=\"lc-chat__thread\">\n @for (msg of formattedMessages(); track msg.id) {\n <div\n class=\"lc-chat__message\"\n [class.lc-chat__message--user]=\"msg.role === 'user'\"\n [class.lc-chat__message--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__message--system]=\"msg.role === 'system'\"\n [class.lc-chat__message--avatar]=\"showUserAvatar(msg)\"\n [class.lc-chat__message--streaming]=\"msg.streaming\"\n [attr.role]=\"msg.status === 'error' ? 'alert' : null\"\n [attr.aria-live]=\"statusAriaLive(msg.status)\"\n >\n @if ((msg.role !== 'user' && (showAvatars() || isSemanticStatus(msg.status))) || showUserAvatar(msg)) {\n <div class=\"lc-chat__marker\" [class.lc-chat__marker--user]=\"msg.role === 'user'\">\n @if (isSemanticStatus(msg.status) && msg.role !== 'user') {\n <span class=\"lc-chat__status-icon\">\n <lc-icon [name]=\"statusIcon(msg.status)\" size=\"xs\" [color]=\"statusColor(msg.status)\" [decorative]=\"true\" />\n </span>\n } @else if (msg.avatar) {\n <img [src]=\"msg.avatar\" [alt]=\"msg.name || msg.role\" class=\"lc-chat__avatar-img\" />\n } @else if (msg.role === 'user') {\n <span class=\"lc-chat__monogram\" [attr.aria-label]=\"msg.name\">{{ initials(msg.name) }}</span>\n } @else {\n <span\n class=\"lc-chat__dot\"\n [class.lc-chat__dot--agent]=\"msg.role === 'agent'\"\n [class.lc-chat__dot--system]=\"msg.role === 'system'\"\n ></span>\n }\n </div>\n }\n\n <div class=\"lc-chat__bubble\" [class.lc-chat__bubble--streaming]=\"msg.streaming\">\n @if (msg.name && msg.role !== 'user') {\n @if (showTimestamps() && msg.timestamp) {\n <div class=\"lc-chat__meta lc-chat__meta--agent\">\n <span class=\"lc-chat__name\">{{ msg.name }}</span>\n <span class=\"lc-chat__time\">{{ formatTime(msg.timestamp) }}</span>\n </div>\n } @else {\n <div class=\"lc-chat__name\">{{ msg.name }}</div>\n }\n }\n <div class=\"lc-chat__content\">\n @if (isSemanticStatus(msg.status)) {\n <span class=\"lc-chat__sr-only\">{{ statusLabel(msg.status) }} </span>\n }\n @if (messageTemplate) {\n <ng-container *ngTemplateOutlet=\"messageTemplate; context: { $implicit: msg }\" />\n } @else if (shouldRenderMarkdown(msg.role)) {\n <lc-markdown [content]=\"msg.content\" variant=\"chat\" />\n } @else {\n {{ msg.content }}\n }\n <span class=\"lc-chat__cursor\" [class.lc-chat__cursor--visible]=\"msg.streaming\"></span>\n </div>\n @if (msg.attachments?.length) {\n <div class=\"lc-chat__attachments\">\n @for (att of msg.attachments; track att.id) {\n @if (isImage(att) && att.url) {\n <a class=\"lc-chat__attachment lc-chat__attachment--image\" [href]=\"att.url\" target=\"_blank\" rel=\"noopener\">\n <img [src]=\"att.url\" [alt]=\"att.name\" />\n </a>\n } @else {\n <a\n class=\"lc-chat__attachment lc-chat__attachment--file\"\n [href]=\"att.url || null\"\n [attr.download]=\"att.url ? att.name : null\"\n target=\"_blank\"\n rel=\"noopener\"\n >\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n <span class=\"lc-chat__attachment-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__attachment-size\">{{ formatBytes(att.size) }}</span>\n }\n </a>\n }\n }\n </div>\n }\n @if (showTimestamps() && msg.timestamp && msg.role !== 'user' && !msg.name) {\n <div class=\"lc-chat__time lc-chat__time--tight\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n @if (showTimestamps() && msg.timestamp && msg.role === 'user') {\n <div class=\"lc-chat__time lc-chat__time--user\">{{ formatTime(msg.timestamp) }}</div>\n }\n </div>\n }\n\n @if (isStreaming() && !(formattedMessages().length && formattedMessages()[formattedMessages().length - 1].streaming)) {\n <div class=\"lc-chat__message lc-chat__message--agent\">\n @if (showAvatars()) {\n <div class=\"lc-chat__marker\">\n <span class=\"lc-chat__dot lc-chat__dot--agent\"></span>\n </div>\n }\n <div class=\"lc-chat__bubble\">\n <div class=\"lc-chat__typing\">\n <span></span><span></span><span></span>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Announces the latest completed non-user turn (see `announcement`). -->\n <div class=\"lc-chat__sr-only lc-chat__announcer\" aria-live=\"polite\" aria-atomic=\"true\">{{ announcement() }}</div>\n\n <div class=\"lc-chat__input-area\">\n <div class=\"lc-chat__composer\">\n @if (allowFileUpload() && pendingAttachments().length) {\n <div class=\"lc-chat__pending-attachments\">\n @for (att of pendingAttachments(); track att.id) {\n <div class=\"lc-chat__pending-attachment\" [class.lc-chat__pending-attachment--image]=\"isImage(att)\">\n @if (isImage(att) && att.url) {\n <img class=\"lc-chat__pending-thumb\" [src]=\"att.url\" [alt]=\"att.name\" />\n } @else {\n <svg class=\"lc-chat__attachment-icon\" width=\"16\" height=\"16\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M6 2.5h6L16 6.5v10A1.5 1.5 0 0 1 14.5 18h-9A1.5 1.5 0 0 1 4 16.5v-12A1.5 1.5 0 0 1 5.5 3H6V2.5Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n <path d=\"M12 2.5V6.5H16\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linejoin=\"round\"/>\n </svg>\n }\n <span class=\"lc-chat__pending-name\">{{ att.name }}</span>\n @if (att.size) {\n <span class=\"lc-chat__pending-size\">{{ formatBytes(att.size) }}</span>\n }\n <button\n type=\"button\"\n class=\"lc-chat__pending-remove\"\n (click)=\"removeAttachment(att.id)\"\n [attr.aria-label]=\"removeAttachmentAriaLabel() + ' ' + att.name\"\n >\n <svg width=\"12\" height=\"12\" viewBox=\"0 0 12 12\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M3 3l6 6M9 3l-6 6\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\"/>\n </svg>\n </button>\n </div>\n }\n </div>\n }\n\n <label class=\"lc-chat__sr-only\" [for]=\"inputId\">{{ inputLabel() }}</label>\n <textarea\n #composerInput\n [id]=\"inputId\"\n class=\"lc-chat__input\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n [disabled]=\"disabled()\"\n (input)=\"onInput($event)\"\n (keydown)=\"onKeydown($event)\"\n rows=\"1\"\n ></textarea>\n\n <div class=\"lc-chat__composer-actions\">\n @if (allowFileUpload()) {\n <input\n #fileInput\n type=\"file\"\n class=\"lc-chat__file-input\"\n [accept]=\"accept() || null\"\n [multiple]=\"multiple()\"\n (change)=\"onFilesSelected($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-chat__attach-btn\"\n [disabled]=\"disabled()\"\n (click)=\"openFilePicker()\"\n [attr.aria-label]=\"attachAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" aria-hidden=\"true\">\n <path d=\"M14.5 9.5l-5 5a3 3 0 0 1-4.243-4.243l6.364-6.364a2 2 0 0 1 2.829 2.829l-6.364 6.364a1 1 0 1 1-1.415-1.415L11.5 6.5\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/>\n </svg>\n </button>\n }\n <button\n class=\"lc-chat__send-btn\"\n [disabled]=\"(!inputValue().trim() && !pendingAttachments().length) || disabled()\"\n (click)=\"send()\"\n [attr.aria-label]=\"sendAriaLabel()\"\n >\n <svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\">\n <path d=\"M3 10l7-7m0 0l7 7m-7-7v14\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" transform=\"rotate(90 10 10)\"/>\n </svg>\n </button>\n </div>\n </div>\n </div>\n</div>\n"],"mappings":"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"}
@@ -529,7 +529,7 @@ var DatepickerComponent = class DatepickerComponent {
529
529
  }],
530
530
  ngImport: i0,
531
531
  template: "<div class=\"lc-datepicker-wrapper\">\n <div class=\"lc-datepicker-input-wrapper\">\n <input\n #datepickerInput\n type=\"text\"\n [id]=\"inputId\"\n [class]=\"datepickerClasses()\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n autocomplete=\"off\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? inputId + '-calendar' : null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n (input)=\"onInputChange(getInputValue($event))\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n />\n <div class=\"lc-datepicker-icons\">\n @if (selectedDate() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n <svg\n class=\"lc-datepicker-calendar-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H6a.75.75 0 01-.75-.75V12zM6 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H6zM7.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H8a.75.75 0 01-.75-.75V12zM8 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H8zM9.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V10zM10 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H10zM9.25 14a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V14zM12 9.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V10a.75.75 0 00-.75-.75H12zM11.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H12a.75.75 0 01-.75-.75V12zM12 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H12zM13.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H14a.75.75 0 01-.75-.75V10zM14 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H14z\"\n />\n <path\n fill-rule=\"evenodd\"\n d=\"M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Calendar Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"datepickerInput\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div\n #calendarPanel\n class=\"lc-datepicker-calendar\"\n [class.lc-datepicker-calendar--open]=\"isOpen()\"\n [id]=\"inputId + '-calendar'\"\n role=\"dialog\"\n [attr.aria-label]=\"dialogAriaLabel()\"\n >\n <!-- Calendar Header -->\n <div class=\"lc-datepicker-header\">\n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"previousMonth()\"\n [attr.aria-label]=\"previousMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n \n <div class=\"lc-datepicker-month-year\" aria-live=\"polite\">\n {{ currentMonthName() }} {{ currentYear() }}\n </div>\n \n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"nextMonth()\"\n [attr.aria-label]=\"nextMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Quick Actions -->\n <div class=\"lc-datepicker-quick-actions\">\n <button\n type=\"button\"\n class=\"lc-datepicker-today-button\"\n (click)=\"goToToday()\"\n >\n {{ todayLabel() }}\n </button>\n </div>\n\n <!-- Weekday Headers -->\n <div class=\"lc-datepicker-weekdays\" aria-hidden=\"true\">\n @for (day of weekdayLabels(); track $index) {\n <div class=\"lc-datepicker-weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Calendar Days -->\n <div class=\"lc-datepicker-days\">\n @for (date of generateCalendarDays(); track date.getTime()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-day\"\n [class.lc-datepicker-day--other-month]=\"!isCurrentMonth(date)\"\n [class.lc-datepicker-day--today]=\"isToday(date)\"\n [class.lc-datepicker-day--selected]=\"isSelectedDate(date)\"\n [class.lc-datepicker-day--disabled]=\"isDateDisabled(date)\"\n [disabled]=\"isDateDisabled(date)\"\n [attr.aria-current]=\"isToday(date) ? 'date' : null\"\n [attr.aria-label]=\"dayAriaLabel(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </button>\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-datepicker__error\" [id]=\"inputId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-datepicker__helper\" [id]=\"inputId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n",
532
- styles: [".lc-datepicker-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-datepicker-input-wrapper{position:relative;width:100%}.lc-datepicker{width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:text}.lc-datepicker::placeholder{color:var(--color-text-secondary)}.lc-datepicker:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){border-color:var(--color-text-secondary)}.lc-datepicker:focus{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-datepicker:disabled{background-color:var(--color-surface-muted);border-color:var(--color-border);cursor:not-allowed;opacity:.6}.lc-datepicker[readonly]{background-color:var(--color-surface-muted);cursor:default}.lc-datepicker.lc-datepicker--error{border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--error:focus{outline-color:var(--color-error-600);border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-xs-font-size)}.lc-datepicker.lc-datepicker--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-sm-font-size)}.lc-datepicker.lc-datepicker--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-14);font-size:var(--size-interactive-md-font-size)}.lc-datepicker.lc-datepicker--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-16);font-size:var(--size-interactive-lg-font-size)}.lc-datepicker.lc-datepicker--filled{background-color:var(--color-surface-sunken);border-color:transparent}.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-border)}.lc-datepicker.lc-datepicker--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500)}.lc-datepicker.lc-datepicker--filled:disabled{background-color:var(--color-surface-muted)}.lc-datepicker-icons{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:var(--spacing-1);pointer-events:none}.lc-datepicker-calendar-icon{width:1.25rem;height:1.25rem;color:var(--color-text-secondary)}.lc-datepicker-clear{pointer-events:auto;display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-clear:hover{color:var(--color-text-primary);background-color:var(--color-surface-hover)}.lc-datepicker-clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-clear svg{width:1rem;height:1rem}.lc-datepicker-calendar{position:absolute;z-index:1000;margin-top:var(--spacing-1);padding:var(--lc-density-padding-md, var(--spacing-4));background-color:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-3);min-width:280px;opacity:0;transform:translateY(-8px);transition:all var(--animation-duration-base) var(--animation-timing-ease);pointer-events:none}.lc-datepicker-calendar.lc-datepicker-calendar--open{opacity:1;transform:translateY(0);pointer-events:auto}.lc-datepicker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-4)}.lc-datepicker-month-year{font-size:var(--font-size-base);font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}.lc-datepicker-nav-button{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-nav-button:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-datepicker-nav-button:active{background-color:var(--color-surface-sunken)}.lc-datepicker-nav-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-nav-button svg{width:1.25rem;height:1.25rem}.lc-datepicker-quick-actions{display:flex;justify-content:center;margin-bottom:var(--spacing-3)}.lc-datepicker-today-button{padding:var(--spacing-1) var(--spacing-3);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-primary-600);background:none;border:1px solid var(--color-primary-200);border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-today-button:hover{background-color:var(--color-primary-50);border-color:var(--color-primary-300)}.lc-datepicker-today-button:active{background-color:var(--color-primary-100)}.lc-datepicker-today-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1);margin-bottom:var(--spacing-2)}.lc-datepicker-weekday{font-size:var(--font-size-xs);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);text-align:center;padding:var(--spacing-1)}.lc-datepicker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1)}.lc-datepicker-day{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;font-size:var(--font-size-sm);font-weight:var(--font-weight-regular);color:var(--color-text-primary);background:none;border:none;border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-day:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-datepicker-day.lc-datepicker-day--other-month{color:var(--color-text-tertiary)}.lc-datepicker-day.lc-datepicker-day--today{font-weight:var(--font-weight-semibold);color:var(--color-primary-600);background-color:var(--color-primary-50)}.lc-datepicker-day.lc-datepicker-day--selected{font-weight:var(--font-weight-semibold);color:var(--color-on-primary);background-color:var(--color-primary-fill)}.lc-datepicker-day.lc-datepicker-day--selected:hover{background-color:var(--color-primary-fill-hover)}.lc-datepicker-day.lc-datepicker-day--disabled{color:var(--color-text-disabled);cursor:not-allowed;opacity:.5}.lc-datepicker-day.lc-datepicker-day--disabled:hover{background:none}.lc-datepicker-day:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-datepicker__error{font-size:var(--font-size-xs);color:var(--color-error-600);margin-top:var(--spacing-1)}.lc-datepicker__helper{font-size:var(--font-size-xs);color:var(--color-text-secondary);margin-top:var(--spacing-1)}\n"],
532
+ styles: [".lc-datepicker-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-datepicker-input-wrapper{position:relative;width:100%}.lc-datepicker{width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:text}.lc-datepicker::placeholder{color:var(--color-text-secondary)}.lc-datepicker:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){border-color:var(--color-text-secondary)}.lc-datepicker:focus{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-datepicker:disabled{background-color:var(--color-surface-muted);border-color:var(--color-border);cursor:not-allowed;opacity:.6}.lc-datepicker[readonly]{background-color:var(--color-surface-muted);cursor:default}.lc-datepicker.lc-datepicker--error{border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--error:focus{outline-color:var(--color-error-600);border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-xs-font-size)}.lc-datepicker.lc-datepicker--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-sm-font-size)}.lc-datepicker.lc-datepicker--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-14);font-size:var(--size-interactive-md-font-size)}.lc-datepicker.lc-datepicker--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-16);font-size:var(--size-interactive-lg-font-size)}.lc-datepicker.lc-datepicker--filled{background-color:var(--color-surface-sunken);border-color:var(--color-field-border)}.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-text-secondary)}.lc-datepicker.lc-datepicker--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500)}.lc-datepicker.lc-datepicker--filled:disabled{background-color:var(--color-surface-muted);border-color:var(--color-border)}.lc-datepicker.lc-datepicker--filled.lc-datepicker--error{border-color:var(--color-error-600)}.lc-datepicker-icons{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:var(--spacing-1);pointer-events:none}.lc-datepicker-calendar-icon{width:1.25rem;height:1.25rem;color:var(--color-text-secondary)}.lc-datepicker-clear{pointer-events:auto;display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-clear:hover{color:var(--color-text-primary);background-color:var(--color-surface-hover)}.lc-datepicker-clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-clear svg{width:1rem;height:1rem}.lc-datepicker-calendar{position:absolute;z-index:1000;margin-top:var(--spacing-1);padding:var(--lc-density-padding-md, var(--spacing-4));background-color:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-3);min-width:280px;opacity:0;transform:translateY(-8px);transition:all var(--animation-duration-base) var(--animation-timing-ease);pointer-events:none}.lc-datepicker-calendar.lc-datepicker-calendar--open{opacity:1;transform:translateY(0);pointer-events:auto}.lc-datepicker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-4)}.lc-datepicker-month-year{font-size:var(--font-size-base);font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}.lc-datepicker-nav-button{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-nav-button:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-datepicker-nav-button:active{background-color:var(--color-surface-sunken)}.lc-datepicker-nav-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-nav-button svg{width:1.25rem;height:1.25rem}.lc-datepicker-quick-actions{display:flex;justify-content:center;margin-bottom:var(--spacing-3)}.lc-datepicker-today-button{padding:var(--spacing-1) var(--spacing-3);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-primary-600);background:none;border:1px solid var(--color-primary-200);border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-today-button:hover{background-color:var(--color-primary-50);border-color:var(--color-primary-300)}.lc-datepicker-today-button:active{background-color:var(--color-primary-100)}.lc-datepicker-today-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1);margin-bottom:var(--spacing-2)}.lc-datepicker-weekday{font-size:var(--font-size-xs);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);text-align:center;padding:var(--spacing-1)}.lc-datepicker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1)}.lc-datepicker-day{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;font-size:var(--font-size-sm);font-weight:var(--font-weight-regular);color:var(--color-text-primary);background:none;border:none;border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-day:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-datepicker-day.lc-datepicker-day--other-month{color:var(--color-text-tertiary)}.lc-datepicker-day.lc-datepicker-day--today{font-weight:var(--font-weight-semibold);color:var(--color-primary-600);background-color:var(--color-primary-50)}.lc-datepicker-day.lc-datepicker-day--selected{font-weight:var(--font-weight-semibold);color:var(--color-on-primary);background-color:var(--color-primary-fill)}.lc-datepicker-day.lc-datepicker-day--selected:hover{background-color:var(--color-primary-fill-hover)}.lc-datepicker-day.lc-datepicker-day--disabled{color:var(--color-text-disabled);cursor:not-allowed;opacity:.5}.lc-datepicker-day.lc-datepicker-day--disabled:hover{background:none}.lc-datepicker-day:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-datepicker__error{font-size:var(--font-size-xs);color:var(--color-error-600);margin-top:var(--spacing-1)}.lc-datepicker__helper{font-size:var(--font-size-xs);color:var(--color-text-secondary);margin-top:var(--spacing-1)}\n"],
533
533
  dependencies: [{
534
534
  kind: "ngmodule",
535
535
  type: OverlayModule
@@ -595,7 +595,7 @@ i0.ɵɵngDeclareClassMetadata({
595
595
  multi: true
596
596
  }],
597
597
  template: "<div class=\"lc-datepicker-wrapper\">\n <div class=\"lc-datepicker-input-wrapper\">\n <input\n #datepickerInput\n type=\"text\"\n [id]=\"inputId\"\n [class]=\"datepickerClasses()\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n autocomplete=\"off\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? inputId + '-calendar' : null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n (input)=\"onInputChange(getInputValue($event))\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n />\n <div class=\"lc-datepicker-icons\">\n @if (selectedDate() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n <svg\n class=\"lc-datepicker-calendar-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H6a.75.75 0 01-.75-.75V12zM6 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H6zM7.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H8a.75.75 0 01-.75-.75V12zM8 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H8zM9.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V10zM10 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H10zM9.25 14a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V14zM12 9.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V10a.75.75 0 00-.75-.75H12zM11.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H12a.75.75 0 01-.75-.75V12zM12 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H12zM13.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H14a.75.75 0 01-.75-.75V10zM14 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H14z\"\n />\n <path\n fill-rule=\"evenodd\"\n d=\"M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Calendar Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"datepickerInput\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div\n #calendarPanel\n class=\"lc-datepicker-calendar\"\n [class.lc-datepicker-calendar--open]=\"isOpen()\"\n [id]=\"inputId + '-calendar'\"\n role=\"dialog\"\n [attr.aria-label]=\"dialogAriaLabel()\"\n >\n <!-- Calendar Header -->\n <div class=\"lc-datepicker-header\">\n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"previousMonth()\"\n [attr.aria-label]=\"previousMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n \n <div class=\"lc-datepicker-month-year\" aria-live=\"polite\">\n {{ currentMonthName() }} {{ currentYear() }}\n </div>\n \n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"nextMonth()\"\n [attr.aria-label]=\"nextMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Quick Actions -->\n <div class=\"lc-datepicker-quick-actions\">\n <button\n type=\"button\"\n class=\"lc-datepicker-today-button\"\n (click)=\"goToToday()\"\n >\n {{ todayLabel() }}\n </button>\n </div>\n\n <!-- Weekday Headers -->\n <div class=\"lc-datepicker-weekdays\" aria-hidden=\"true\">\n @for (day of weekdayLabels(); track $index) {\n <div class=\"lc-datepicker-weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Calendar Days -->\n <div class=\"lc-datepicker-days\">\n @for (date of generateCalendarDays(); track date.getTime()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-day\"\n [class.lc-datepicker-day--other-month]=\"!isCurrentMonth(date)\"\n [class.lc-datepicker-day--today]=\"isToday(date)\"\n [class.lc-datepicker-day--selected]=\"isSelectedDate(date)\"\n [class.lc-datepicker-day--disabled]=\"isDateDisabled(date)\"\n [disabled]=\"isDateDisabled(date)\"\n [attr.aria-current]=\"isToday(date) ? 'date' : null\"\n [attr.aria-label]=\"dayAriaLabel(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </button>\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-datepicker__error\" [id]=\"inputId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-datepicker__helper\" [id]=\"inputId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n",
598
- styles: [".lc-datepicker-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-datepicker-input-wrapper{position:relative;width:100%}.lc-datepicker{width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:text}.lc-datepicker::placeholder{color:var(--color-text-secondary)}.lc-datepicker:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){border-color:var(--color-text-secondary)}.lc-datepicker:focus{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-datepicker:disabled{background-color:var(--color-surface-muted);border-color:var(--color-border);cursor:not-allowed;opacity:.6}.lc-datepicker[readonly]{background-color:var(--color-surface-muted);cursor:default}.lc-datepicker.lc-datepicker--error{border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--error:focus{outline-color:var(--color-error-600);border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-xs-font-size)}.lc-datepicker.lc-datepicker--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-sm-font-size)}.lc-datepicker.lc-datepicker--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-14);font-size:var(--size-interactive-md-font-size)}.lc-datepicker.lc-datepicker--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-16);font-size:var(--size-interactive-lg-font-size)}.lc-datepicker.lc-datepicker--filled{background-color:var(--color-surface-sunken);border-color:transparent}.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-border)}.lc-datepicker.lc-datepicker--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500)}.lc-datepicker.lc-datepicker--filled:disabled{background-color:var(--color-surface-muted)}.lc-datepicker-icons{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:var(--spacing-1);pointer-events:none}.lc-datepicker-calendar-icon{width:1.25rem;height:1.25rem;color:var(--color-text-secondary)}.lc-datepicker-clear{pointer-events:auto;display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-clear:hover{color:var(--color-text-primary);background-color:var(--color-surface-hover)}.lc-datepicker-clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-clear svg{width:1rem;height:1rem}.lc-datepicker-calendar{position:absolute;z-index:1000;margin-top:var(--spacing-1);padding:var(--lc-density-padding-md, var(--spacing-4));background-color:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-3);min-width:280px;opacity:0;transform:translateY(-8px);transition:all var(--animation-duration-base) var(--animation-timing-ease);pointer-events:none}.lc-datepicker-calendar.lc-datepicker-calendar--open{opacity:1;transform:translateY(0);pointer-events:auto}.lc-datepicker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-4)}.lc-datepicker-month-year{font-size:var(--font-size-base);font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}.lc-datepicker-nav-button{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-nav-button:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-datepicker-nav-button:active{background-color:var(--color-surface-sunken)}.lc-datepicker-nav-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-nav-button svg{width:1.25rem;height:1.25rem}.lc-datepicker-quick-actions{display:flex;justify-content:center;margin-bottom:var(--spacing-3)}.lc-datepicker-today-button{padding:var(--spacing-1) var(--spacing-3);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-primary-600);background:none;border:1px solid var(--color-primary-200);border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-today-button:hover{background-color:var(--color-primary-50);border-color:var(--color-primary-300)}.lc-datepicker-today-button:active{background-color:var(--color-primary-100)}.lc-datepicker-today-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1);margin-bottom:var(--spacing-2)}.lc-datepicker-weekday{font-size:var(--font-size-xs);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);text-align:center;padding:var(--spacing-1)}.lc-datepicker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1)}.lc-datepicker-day{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;font-size:var(--font-size-sm);font-weight:var(--font-weight-regular);color:var(--color-text-primary);background:none;border:none;border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-day:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-datepicker-day.lc-datepicker-day--other-month{color:var(--color-text-tertiary)}.lc-datepicker-day.lc-datepicker-day--today{font-weight:var(--font-weight-semibold);color:var(--color-primary-600);background-color:var(--color-primary-50)}.lc-datepicker-day.lc-datepicker-day--selected{font-weight:var(--font-weight-semibold);color:var(--color-on-primary);background-color:var(--color-primary-fill)}.lc-datepicker-day.lc-datepicker-day--selected:hover{background-color:var(--color-primary-fill-hover)}.lc-datepicker-day.lc-datepicker-day--disabled{color:var(--color-text-disabled);cursor:not-allowed;opacity:.5}.lc-datepicker-day.lc-datepicker-day--disabled:hover{background:none}.lc-datepicker-day:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-datepicker__error{font-size:var(--font-size-xs);color:var(--color-error-600);margin-top:var(--spacing-1)}.lc-datepicker__helper{font-size:var(--font-size-xs);color:var(--color-text-secondary);margin-top:var(--spacing-1)}\n"]
598
+ styles: [".lc-datepicker-wrapper{display:flex;flex-direction:column;gap:var(--lc-density-gap-xs, var(--spacing-1));width:100%;position:relative}.lc-datepicker-input-wrapper{position:relative;width:100%}.lc-datepicker{width:100%;font-family:var(--font-family-sans);font-weight:var(--font-weight-regular);line-height:var(--line-height-normal);color:var(--color-text-primary);background-color:var(--color-surface);border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);transition:all var(--animation-duration-base) var(--animation-timing-ease);cursor:text}.lc-datepicker::placeholder{color:var(--color-text-secondary)}.lc-datepicker:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){border-color:var(--color-text-secondary)}.lc-datepicker:focus{outline:2px solid var(--color-primary-500);outline-offset:0px;border-color:var(--color-primary-500)}.lc-datepicker:disabled{background-color:var(--color-surface-muted);border-color:var(--color-border);cursor:not-allowed;opacity:.6}.lc-datepicker[readonly]{background-color:var(--color-surface-muted);cursor:default}.lc-datepicker.lc-datepicker--error{border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--error:focus{outline-color:var(--color-error-600);border-color:var(--color-error-600)}.lc-datepicker.lc-datepicker--xs{height:var(--size-interactive-xs-height);padding:var(--size-interactive-xs-padding);padding-right:var(--spacing-10);font-size:var(--size-interactive-xs-font-size)}.lc-datepicker.lc-datepicker--sm{height:var(--size-interactive-sm-height);padding:var(--size-interactive-sm-padding);padding-right:var(--spacing-12);font-size:var(--size-interactive-sm-font-size)}.lc-datepicker.lc-datepicker--md{height:var(--size-interactive-md-height);padding:var(--size-interactive-md-padding);padding-right:var(--spacing-14);font-size:var(--size-interactive-md-font-size)}.lc-datepicker.lc-datepicker--lg{height:var(--size-interactive-lg-height);padding:var(--size-interactive-lg-padding);padding-right:var(--spacing-16);font-size:var(--size-interactive-lg-font-size)}.lc-datepicker.lc-datepicker--filled{background-color:var(--color-surface-sunken);border-color:var(--color-field-border)}.lc-datepicker.lc-datepicker--filled:hover:not(:disabled):not([readonly]):not(.lc-datepicker--error):not(:focus){background-color:var(--color-surface-hover);border-color:var(--color-text-secondary)}.lc-datepicker.lc-datepicker--filled:focus{background-color:var(--color-surface);border-color:var(--color-primary-500)}.lc-datepicker.lc-datepicker--filled:disabled{background-color:var(--color-surface-muted);border-color:var(--color-border)}.lc-datepicker.lc-datepicker--filled.lc-datepicker--error{border-color:var(--color-error-600)}.lc-datepicker-icons{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);display:flex;align-items:center;gap:var(--spacing-1);pointer-events:none}.lc-datepicker-calendar-icon{width:1.25rem;height:1.25rem;color:var(--color-text-secondary)}.lc-datepicker-clear{pointer-events:auto;display:flex;align-items:center;justify-content:center;width:1.25rem;height:1.25rem;padding:0;background:none;border:none;border-radius:var(--border-radius-sm);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-clear:hover{color:var(--color-text-primary);background-color:var(--color-surface-hover)}.lc-datepicker-clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-clear svg{width:1rem;height:1rem}.lc-datepicker-calendar{position:absolute;z-index:1000;margin-top:var(--spacing-1);padding:var(--lc-density-padding-md, var(--spacing-4));background-color:var(--color-surface);border:1px solid var(--color-border);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-3);min-width:280px;opacity:0;transform:translateY(-8px);transition:all var(--animation-duration-base) var(--animation-timing-ease);pointer-events:none}.lc-datepicker-calendar.lc-datepicker-calendar--open{opacity:1;transform:translateY(0);pointer-events:auto}.lc-datepicker-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--spacing-4)}.lc-datepicker-month-year{font-size:var(--font-size-base);font-weight:var(--font-weight-semibold);color:var(--color-text-primary)}.lc-datepicker-nav-button{display:flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;background:none;border:none;border-radius:var(--border-radius-md);color:var(--color-text-secondary);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-nav-button:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-datepicker-nav-button:active{background-color:var(--color-surface-sunken)}.lc-datepicker-nav-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-nav-button svg{width:1.25rem;height:1.25rem}.lc-datepicker-quick-actions{display:flex;justify-content:center;margin-bottom:var(--spacing-3)}.lc-datepicker-today-button{padding:var(--spacing-1) var(--spacing-3);font-size:var(--font-size-sm);font-weight:var(--font-weight-medium);color:var(--color-primary-600);background:none;border:1px solid var(--color-primary-200);border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-today-button:hover{background-color:var(--color-primary-50);border-color:var(--color-primary-300)}.lc-datepicker-today-button:active{background-color:var(--color-primary-100)}.lc-datepicker-today-button:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:1px}.lc-datepicker-weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1);margin-bottom:var(--spacing-2)}.lc-datepicker-weekday{font-size:var(--font-size-xs);font-weight:var(--font-weight-semibold);color:var(--color-text-secondary);text-align:center;padding:var(--spacing-1)}.lc-datepicker-days{display:grid;grid-template-columns:repeat(7,1fr);gap:var(--spacing-1)}.lc-datepicker-day{display:flex;align-items:center;justify-content:center;width:2.25rem;height:2.25rem;padding:0;font-size:var(--font-size-sm);font-weight:var(--font-weight-regular);color:var(--color-text-primary);background:none;border:none;border-radius:var(--border-radius-md);cursor:pointer;transition:all var(--animation-duration-fast) var(--animation-timing-ease)}.lc-datepicker-day:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-datepicker-day.lc-datepicker-day--other-month{color:var(--color-text-tertiary)}.lc-datepicker-day.lc-datepicker-day--today{font-weight:var(--font-weight-semibold);color:var(--color-primary-600);background-color:var(--color-primary-50)}.lc-datepicker-day.lc-datepicker-day--selected{font-weight:var(--font-weight-semibold);color:var(--color-on-primary);background-color:var(--color-primary-fill)}.lc-datepicker-day.lc-datepicker-day--selected:hover{background-color:var(--color-primary-fill-hover)}.lc-datepicker-day.lc-datepicker-day--disabled{color:var(--color-text-disabled);cursor:not-allowed;opacity:.5}.lc-datepicker-day.lc-datepicker-day--disabled:hover{background:none}.lc-datepicker-day:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:2px}.lc-datepicker__error{font-size:var(--font-size-xs);color:var(--color-error-600);margin-top:var(--spacing-1)}.lc-datepicker__helper{font-size:var(--font-size-xs);color:var(--color-text-secondary);margin-top:var(--spacing-1)}\n"]
599
599
  }]
600
600
  }],
601
601
  propDecorators: {
@@ -1 +1 @@
1
- {"version":3,"file":"lifecorner-angular-ui-kit-datepicker.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/datepicker/datepicker.component.ts","../../../../libs/angular-ui-kit/src/lib/datepicker/datepicker.component.html"],"sourcesContent":["import {\n Component,\n input,\n output,\n signal,\n computed,\n linkedSignal,\n ChangeDetectionStrategy,\n forwardRef,\n ElementRef,\n viewChild,\n inject,\n DOCUMENT,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\nexport type DateValue = Date | string | null;\n\n/**\n * Datepicker component for date selection with calendar overlay.\n *\n * Features:\n * - Calendar popup with month and year navigation\n * - Manual date entry in the configured format\n * - Min/max date constraints\n * - Disabled specific dates and weekends\n * - Configurable date format string\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Disabled and readonly states\n * - ControlValueAccessor integration for reactive forms\n *\n * @example\n * ```html\n * <lc-datepicker placeholder=\"Select date\" [(ngModel)]=\"selectedDate\" />\n * ```\n */\n@Component({\n selector: 'lc-datepicker',\n standalone: true,\n imports: [OverlayModule],\n templateUrl: './datepicker.component.html',\n styleUrl: './datepicker.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DatepickerComponent),\n multi: true,\n },\n ],\n})\nexport class DatepickerComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance id for the input; helper/error text ids derive from it. */\n readonly inputId = `lc-datepicker-${++DatepickerComponent.nextId}`;\n\n private readonly datepickerInput = viewChild<ElementRef<HTMLInputElement>>('datepickerInput');\n private readonly calendarPanel = viewChild<ElementRef<HTMLElement>>('calendarPanel');\n\n /**\n * Visual variant of the datepicker\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the datepicker\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the datepicker is disabled\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the datepicker is in error state\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the datepicker is required\n */\n readonly required = input<boolean>(false);\n\n /**\n * Whether the datepicker is readonly\n */\n readonly readonly = input<boolean>(false);\n\n /**\n * Placeholder text\n */\n readonly placeholder = input<string>('Select a date');\n\n /**\n * Helper text displayed below the datepicker\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Date format string (e.g., 'YYYY-MM-DD', 'MM/DD/YYYY')\n */\n readonly format = input<string>('YYYY-MM-DD');\n\n /**\n * Minimum selectable date (compared by calendar day, time of day is ignored)\n */\n readonly minDate = input<Date | undefined>(undefined);\n\n /**\n * Maximum selectable date (compared by calendar day, time of day is ignored)\n */\n readonly maxDate = input<Date | undefined>(undefined);\n\n /**\n * Array of disabled dates\n */\n readonly disabledDates = input<Date[]>([]);\n\n /**\n * Whether to disable weekends\n */\n readonly disableWeekends = input<boolean>(false);\n\n /** BCP 47 locale for month and weekday names and the day buttons' accessible names (e.g. `'de-DE'`). Empty keeps the built-in English names. */\n readonly locale = input('');\n\n /** First column of the grid: 0 Sunday (default) … 6 Saturday — 1 for Monday. */\n readonly firstDayOfWeek = input(0);\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear date');\n\n /** Accessible name of the calendar dialog. */\n readonly dialogAriaLabel = input('Choose date');\n\n /** Accessible name of the previous-month button. */\n readonly previousMonthAriaLabel = input('Previous month');\n\n /** Accessible name of the next-month button. */\n readonly nextMonthAriaLabel = input('Next month');\n\n /** Label of the \"go to today\" button. */\n readonly todayLabel = input('Today');\n\n /** Appended to the selected day's accessible name (`…, selected`). */\n readonly selectedAriaLabel = input('selected');\n\n /**\n * Emitted when date selection changes\n */\n readonly dateChange = output<Date | null>();\n\n /**\n * Emitted when calendar opens\n */\n readonly opened = output<void>();\n\n /**\n * Emitted when calendar closes\n */\n readonly closed = output<void>();\n\n // Internal state\n readonly selectedDate = signal<Date | null>(null);\n readonly isOpen = signal<boolean>(false);\n readonly currentMonth = signal<number>(new Date().getMonth());\n readonly currentYear = signal<number>(new Date().getFullYear());\n\n /** Disabled state pushed in by the forms API (setDisabledState). */\n private readonly formDisabled = signal<boolean>(false);\n\n /** Effective disabled state: the `disabled` input OR the form control's disabled state. */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly formattedDate = computed(() => {\n const date = this.selectedDate();\n if (!date) return '';\n return this.formatDate(date, this.format());\n });\n\n /**\n * Text currently shown in the input. Follows the selected date, but the user\n * can type freely; only a complete, valid date is committed to the model.\n */\n readonly inputValue = linkedSignal(() => this.formattedDate());\n\n weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];\n\n monthNames = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ];\n\n /** Month name in the header: `locale` when set, the English names otherwise. */\n readonly currentMonthName = computed(() => {\n const locale = this.locale();\n return locale\n ? new Date(this.currentYear(), this.currentMonth(), 1).toLocaleDateString(locale, { month: 'long' })\n : this.monthNames[this.currentMonth()];\n });\n\n /** Weekday headers in grid order, starting at `firstDayOfWeek`. */\n readonly weekdayLabels = computed(() => {\n const locale = this.locale();\n const first = this.gridStart();\n // 1 Jan 2023 was a Sunday, so day d of that week has getDay() === d.\n const names = locale\n ? Array.from({ length: 7 }, (_, d) =>\n new Date(2023, 0, 1 + d).toLocaleDateString(locale, { weekday: 'short' }).replace(/\\.$/, ''),\n )\n : this.weekDays;\n return Array.from({ length: 7 }, (_, i) => names[(first + i) % 7]);\n });\n\n /** `firstDayOfWeek` clamped to 0–6. */\n private readonly gridStart = computed(() => {\n const day = Math.trunc(Number(this.firstDayOfWeek()));\n return Number.isFinite(day) ? ((day % 7) + 7) % 7 : 0;\n });\n\n /** id of the helper/error text the input is described by (aria-describedby) */\n readonly describedBy = computed(() => {\n if (this.error() && this.errorMessage()) {\n return `${this.inputId}-error`;\n }\n return this.helperText() ? `${this.inputId}-helper` : null;\n });\n\n /**\n * Computed classes for the datepicker input element\n */\n readonly datepickerClasses = computed(() => {\n const classes = [\n 'lc-datepicker',\n `lc-datepicker--${this.variant()}`,\n `lc-datepicker--${this.size()}`,\n ];\n\n if (this.isDisabled()) {\n classes.push('lc-datepicker--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-datepicker--error');\n }\n\n if (this.readonly()) {\n classes.push('lc-datepicker--readonly');\n }\n\n if (this.isOpen()) {\n classes.push('lc-datepicker--open');\n }\n\n return classes.join(' ');\n });\n\n // Private properties\n private readonly document = inject(DOCUMENT);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: Date | null) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n // Public methods\n /**\n * Toggle calendar open/closed\n */\n toggle(): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n if (this.isOpen()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Open calendar\n */\n open(): void {\n if (this.isDisabled() || this.readonly() || this.isOpen()) {\n return;\n }\n this.isOpen.set(true);\n\n // Set calendar to selected date's month/year or current\n const date = this.selectedDate();\n if (date) {\n this.showMonthOf(date);\n }\n\n this.opened.emit();\n }\n\n /**\n * Close calendar. Idempotent: the overlay's `detach` re-enters here after\n * `isOpen` flips, and that second call must not emit `closed` again.\n */\n close(): void {\n if (!this.isOpen()) {\n return;\n }\n // A day button inside the panel may hold focus; it is about to be removed,\n // so hand focus back to the input instead of letting it drop to <body>.\n this.restoreFocusFromPanel();\n this.isOpen.set(false);\n this.closed.emit();\n }\n\n /**\n * Select a date\n */\n selectDate(date: Date): void {\n if (this.isDisabled() || this.readonly() || this.isDateDisabled(date)) {\n return;\n }\n\n this.commitDate(date);\n this.close();\n }\n\n /**\n * Clear selected date\n */\n clear(): void {\n this.selectedDate.set(null);\n this.inputValue.set('');\n this.onChange(null);\n this.dateChange.emit(null);\n }\n\n /**\n * Check if a date is disabled\n */\n isDateDisabled(date: Date): boolean {\n // min/max are compared by calendar day: consumers typically pass `new Date()`\n // (which carries the current time) while calendar cells sit at midnight.\n const day = this.startOfDay(date);\n\n const min = this.minDate();\n if (min && day < this.startOfDay(min)) {\n return true;\n }\n\n const max = this.maxDate();\n if (max && day > this.startOfDay(max)) {\n return true;\n }\n\n // Check disabled dates\n if (this.disabledDates().some((d) => this.isSameDate(d, date))) {\n return true;\n }\n\n // Check weekends\n if (this.disableWeekends()) {\n const weekday = date.getDay();\n if (weekday === 0 || weekday === 6) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Check if date is today\n */\n isToday(date: Date): boolean {\n const today = new Date();\n return this.isSameDate(date, today);\n }\n\n /** Accessible name of a day button: the full date, plus `selectedAriaLabel` when selected. */\n protected dayAriaLabel(date: Date): string {\n const locale = this.locale();\n const name = locale\n ? date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n : date.toDateString();\n return this.isSelectedDate(date) ? `${name}, ${this.selectedAriaLabel()}` : name;\n }\n\n /**\n * Check if date is selected\n */\n isSelectedDate(date: Date): boolean {\n const selected = this.selectedDate();\n return selected ? this.isSameDate(date, selected) : false;\n }\n\n /**\n * Generate calendar days for current month\n */\n generateCalendarDays(): Date[] {\n const year = this.currentYear();\n const month = this.currentMonth();\n\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n\n const days: Date[] = [];\n\n // Add previous month's days, so the first column is `firstDayOfWeek`.\n const leadingDays = (firstDay.getDay() - this.gridStart() + 7) % 7;\n for (let i = leadingDays - 1; i >= 0; i--) {\n const date = new Date(year, month, -i);\n days.push(date);\n }\n\n // Add current month's days\n for (let i = 1; i <= lastDay.getDate(); i++) {\n days.push(new Date(year, month, i));\n }\n\n // Add next month's days to complete the grid\n const remainingDays = 42 - days.length; // 6 weeks * 7 days\n for (let i = 1; i <= remainingDays; i++) {\n days.push(new Date(year, month + 1, i));\n }\n\n return days.slice(0, 42); // Ensure exactly 42 days (6 weeks)\n }\n\n /**\n * Navigate to next month\n */\n nextMonth(): void {\n if (this.currentMonth() === 11) {\n this.currentMonth.set(0);\n this.currentYear.set(this.currentYear() + 1);\n } else {\n this.currentMonth.set(this.currentMonth() + 1);\n }\n }\n\n /**\n * Navigate to previous month\n */\n previousMonth(): void {\n if (this.currentMonth() === 0) {\n this.currentMonth.set(11);\n this.currentYear.set(this.currentYear() - 1);\n } else {\n this.currentMonth.set(this.currentMonth() - 1);\n }\n }\n\n /**\n * Navigate to today\n */\n goToToday(): void {\n this.showMonthOf(new Date());\n }\n\n /**\n * Handle input change (manual date entry). Partial input is kept as text\n * only; the model changes once the text is a complete, valid, selectable date.\n */\n onInputChange(value: string): void {\n this.inputValue.set(value);\n\n if (value.trim() === '') {\n if (this.selectedDate() !== null) {\n this.clear();\n }\n return;\n }\n\n const date = this.parseDate(value, this.format());\n if (date && !this.isDateDisabled(date) && !this.isSelectedDate(date)) {\n this.commitDate(date);\n this.showMonthOf(date);\n }\n }\n\n /**\n * Handle keyboard navigation\n */\n onKeyDown(event: KeyboardEvent): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n\n if (\n !this.isOpen() &&\n (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ')\n ) {\n this.open();\n event.preventDefault();\n return;\n }\n\n if (!this.isOpen()) return;\n\n // While the text differs from the model the user is mid-edit: arrows must\n // move the caret, not the calendar selection.\n const editing = this.inputValue() !== this.formattedDate();\n const currentDate = this.selectedDate() || new Date();\n let newDate: Date | null = null;\n\n switch (event.key) {\n case 'Escape':\n this.close();\n event.preventDefault();\n // Only this datepicker should react; keep the key from reaching enclosing overlays.\n event.stopPropagation();\n break;\n\n case 'ArrowRight':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() + 1);\n event.preventDefault();\n break;\n\n case 'ArrowLeft':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() - 1);\n event.preventDefault();\n break;\n\n case 'ArrowDown':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() + 7);\n event.preventDefault();\n break;\n\n case 'ArrowUp':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() - 7);\n event.preventDefault();\n break;\n\n case 'Enter': {\n const selected = this.selectedDate();\n if (selected) {\n this.selectDate(selected);\n }\n event.preventDefault();\n break;\n }\n }\n\n if (newDate && !this.isDateDisabled(newDate)) {\n this.selectedDate.set(newDate);\n this.showMonthOf(newDate);\n }\n }\n\n /**\n * Handle blur event: mark touched and drop any partial text that never became a date.\n */\n onBlur(): void {\n this.onTouched();\n this.inputValue.set(this.formattedDate());\n }\n\n /**\n * Handle click outside\n */\n onClickOutside(): void {\n this.close();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: DateValue): void {\n let date: Date | null = null;\n if (value instanceof Date) {\n date = isNaN(value.getTime()) ? null : value;\n } else if (typeof value === 'string') {\n date = this.parseDate(value, this.format());\n }\n this.selectedDate.set(date);\n this.inputValue.set(this.formattedDate());\n }\n\n registerOnChange(fn: (value: Date | null) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n /**\n * Check if date is in current month\n */\n isCurrentMonth(date: Date): boolean {\n return date.getMonth() === this.currentMonth() && date.getFullYear() === this.currentYear();\n }\n\n // Private helper methods\n private commitDate(date: Date): void {\n this.selectedDate.set(date);\n this.inputValue.set(this.formatDate(date, this.format()));\n this.onChange(date);\n this.dateChange.emit(date);\n }\n\n private showMonthOf(date: Date): void {\n this.currentMonth.set(date.getMonth());\n this.currentYear.set(date.getFullYear());\n }\n\n private restoreFocusFromPanel(): void {\n const panel = this.calendarPanel()?.nativeElement;\n const active = this.document.activeElement;\n if (panel && active && panel.contains(active)) {\n this.datepickerInput()?.nativeElement.focus();\n }\n }\n\n private startOfDay(date: Date): number {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n }\n\n /**\n * Check if two dates are the same day\n */\n private isSameDate(date1: Date, date2: Date): boolean {\n return (\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n );\n }\n\n private formatDate(date: Date, format: string): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return format.replace('YYYY', String(year)).replace('MM', month).replace('DD', day);\n }\n\n /**\n * Strict parse: the text must match the format's length, carry digits at the\n * YYYY/MM/DD positions and round-trip through formatDate (which rejects\n * things like month 13 or Feb 31 that `new Date` would silently roll over).\n * Returns null for partial or invalid input.\n */\n private parseDate(value: string, format: string): Date | null {\n if (value.length !== format.length) {\n return null;\n }\n\n const yearIndex = format.indexOf('YYYY');\n const monthIndex = format.indexOf('MM');\n const dayIndex = format.indexOf('DD');\n if (yearIndex < 0 || monthIndex < 0 || dayIndex < 0) {\n return null;\n }\n\n const yearText = value.substring(yearIndex, yearIndex + 4);\n const monthText = value.substring(monthIndex, monthIndex + 2);\n const dayText = value.substring(dayIndex, dayIndex + 2);\n if (!/^\\d{4}$/.test(yearText) || !/^\\d{2}$/.test(monthText) || !/^\\d{2}$/.test(dayText)) {\n return null;\n }\n\n const date = new Date(Number(yearText), Number(monthText) - 1, Number(dayText));\n return this.formatDate(date, format) === value ? date : null;\n }\n\n protected getInputValue(event: Event): string {\n return (event.target as HTMLInputElement).value;\n }\n}\n","<div class=\"lc-datepicker-wrapper\">\n <div class=\"lc-datepicker-input-wrapper\">\n <input\n #datepickerInput\n type=\"text\"\n [id]=\"inputId\"\n [class]=\"datepickerClasses()\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n autocomplete=\"off\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? inputId + '-calendar' : null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n (input)=\"onInputChange(getInputValue($event))\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n />\n <div class=\"lc-datepicker-icons\">\n @if (selectedDate() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n <svg\n class=\"lc-datepicker-calendar-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H6a.75.75 0 01-.75-.75V12zM6 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H6zM7.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H8a.75.75 0 01-.75-.75V12zM8 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H8zM9.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V10zM10 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H10zM9.25 14a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V14zM12 9.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V10a.75.75 0 00-.75-.75H12zM11.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H12a.75.75 0 01-.75-.75V12zM12 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H12zM13.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H14a.75.75 0 01-.75-.75V10zM14 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H14z\"\n />\n <path\n fill-rule=\"evenodd\"\n d=\"M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Calendar Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"datepickerInput\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div\n #calendarPanel\n class=\"lc-datepicker-calendar\"\n [class.lc-datepicker-calendar--open]=\"isOpen()\"\n [id]=\"inputId + '-calendar'\"\n role=\"dialog\"\n [attr.aria-label]=\"dialogAriaLabel()\"\n >\n <!-- Calendar Header -->\n <div class=\"lc-datepicker-header\">\n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"previousMonth()\"\n [attr.aria-label]=\"previousMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n \n <div class=\"lc-datepicker-month-year\" aria-live=\"polite\">\n {{ currentMonthName() }} {{ currentYear() }}\n </div>\n \n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"nextMonth()\"\n [attr.aria-label]=\"nextMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Quick Actions -->\n <div class=\"lc-datepicker-quick-actions\">\n <button\n type=\"button\"\n class=\"lc-datepicker-today-button\"\n (click)=\"goToToday()\"\n >\n {{ todayLabel() }}\n </button>\n </div>\n\n <!-- Weekday Headers -->\n <div class=\"lc-datepicker-weekdays\" aria-hidden=\"true\">\n @for (day of weekdayLabels(); track $index) {\n <div class=\"lc-datepicker-weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Calendar Days -->\n <div class=\"lc-datepicker-days\">\n @for (date of generateCalendarDays(); track date.getTime()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-day\"\n [class.lc-datepicker-day--other-month]=\"!isCurrentMonth(date)\"\n [class.lc-datepicker-day--today]=\"isToday(date)\"\n [class.lc-datepicker-day--selected]=\"isSelectedDate(date)\"\n [class.lc-datepicker-day--disabled]=\"isDateDisabled(date)\"\n [disabled]=\"isDateDisabled(date)\"\n [attr.aria-current]=\"isToday(date) ? 'date' : null\"\n [attr.aria-label]=\"dayAriaLabel(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </button>\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-datepicker__error\" [id]=\"inputId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-datepicker__helper\" [id]=\"inputId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n"],"mappings":"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"}
1
+ {"version":3,"file":"lifecorner-angular-ui-kit-datepicker.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/datepicker/datepicker.component.ts","../../../../libs/angular-ui-kit/src/lib/datepicker/datepicker.component.html"],"sourcesContent":["import {\n Component,\n input,\n output,\n signal,\n computed,\n linkedSignal,\n ChangeDetectionStrategy,\n forwardRef,\n ElementRef,\n viewChild,\n inject,\n DOCUMENT,\n} from '@angular/core';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\n\nexport type DateValue = Date | string | null;\n\n/**\n * Datepicker component for date selection with calendar overlay.\n *\n * Features:\n * - Calendar popup with month and year navigation\n * - Manual date entry in the configured format\n * - Min/max date constraints\n * - Disabled specific dates and weekends\n * - Configurable date format string\n * - Variant styles (outline, filled)\n * - Size presets (xs, sm, md, lg)\n * - Disabled and readonly states\n * - ControlValueAccessor integration for reactive forms\n *\n * @example\n * ```html\n * <lc-datepicker placeholder=\"Select date\" [(ngModel)]=\"selectedDate\" />\n * ```\n */\n@Component({\n selector: 'lc-datepicker',\n standalone: true,\n imports: [OverlayModule],\n templateUrl: './datepicker.component.html',\n styleUrl: './datepicker.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DatepickerComponent),\n multi: true,\n },\n ],\n})\nexport class DatepickerComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance id for the input; helper/error text ids derive from it. */\n readonly inputId = `lc-datepicker-${++DatepickerComponent.nextId}`;\n\n private readonly datepickerInput = viewChild<ElementRef<HTMLInputElement>>('datepickerInput');\n private readonly calendarPanel = viewChild<ElementRef<HTMLElement>>('calendarPanel');\n\n /**\n * Visual variant of the datepicker\n */\n readonly variant = input<'outline' | 'filled'>('outline');\n\n /**\n * Size of the datepicker\n */\n readonly size = input<'xs' | 'sm' | 'md' | 'lg'>('md');\n\n /**\n * Whether the datepicker is disabled\n */\n readonly disabled = input<boolean>(false);\n\n /**\n * Whether the datepicker is in error state\n */\n readonly error = input<boolean>(false);\n\n /**\n * Whether the datepicker is required\n */\n readonly required = input<boolean>(false);\n\n /**\n * Whether the datepicker is readonly\n */\n readonly readonly = input<boolean>(false);\n\n /**\n * Placeholder text\n */\n readonly placeholder = input<string>('Select a date');\n\n /**\n * Helper text displayed below the datepicker\n */\n readonly helperText = input<string>('');\n\n /**\n * Error message displayed when error is true\n */\n readonly errorMessage = input<string>('');\n\n /**\n * ARIA label for accessibility\n */\n readonly ariaLabel = input<string | undefined>(undefined);\n\n /**\n * Date format string (e.g., 'YYYY-MM-DD', 'MM/DD/YYYY')\n */\n readonly format = input<string>('YYYY-MM-DD');\n\n /**\n * Minimum selectable date (compared by calendar day, time of day is ignored)\n */\n readonly minDate = input<Date | undefined>(undefined);\n\n /**\n * Maximum selectable date (compared by calendar day, time of day is ignored)\n */\n readonly maxDate = input<Date | undefined>(undefined);\n\n /**\n * Array of disabled dates\n */\n readonly disabledDates = input<Date[]>([]);\n\n /**\n * Whether to disable weekends\n */\n readonly disableWeekends = input<boolean>(false);\n\n /** BCP 47 locale for month and weekday names and the day buttons' accessible names (e.g. `'de-DE'`). Empty keeps the built-in English names. */\n readonly locale = input('');\n\n /** First column of the grid: 0 Sunday (default) … 6 Saturday — 1 for Monday. */\n readonly firstDayOfWeek = input(0);\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear date');\n\n /** Accessible name of the calendar dialog. */\n readonly dialogAriaLabel = input('Choose date');\n\n /** Accessible name of the previous-month button. */\n readonly previousMonthAriaLabel = input('Previous month');\n\n /** Accessible name of the next-month button. */\n readonly nextMonthAriaLabel = input('Next month');\n\n /** Label of the \"go to today\" button. */\n readonly todayLabel = input('Today');\n\n /** Appended to the selected day's accessible name (`…, selected`). */\n readonly selectedAriaLabel = input('selected');\n\n /**\n * Emitted when date selection changes\n */\n readonly dateChange = output<Date | null>();\n\n /**\n * Emitted when calendar opens\n */\n readonly opened = output<void>();\n\n /**\n * Emitted when calendar closes\n */\n readonly closed = output<void>();\n\n // Internal state\n readonly selectedDate = signal<Date | null>(null);\n readonly isOpen = signal<boolean>(false);\n readonly currentMonth = signal<number>(new Date().getMonth());\n readonly currentYear = signal<number>(new Date().getFullYear());\n\n /** Disabled state pushed in by the forms API (setDisabledState). */\n private readonly formDisabled = signal<boolean>(false);\n\n /** Effective disabled state: the `disabled` input OR the form control's disabled state. */\n readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n // Computed values\n readonly formattedDate = computed(() => {\n const date = this.selectedDate();\n if (!date) return '';\n return this.formatDate(date, this.format());\n });\n\n /**\n * Text currently shown in the input. Follows the selected date, but the user\n * can type freely; only a complete, valid date is committed to the model.\n */\n readonly inputValue = linkedSignal(() => this.formattedDate());\n\n weekDays = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];\n\n monthNames = [\n 'January',\n 'February',\n 'March',\n 'April',\n 'May',\n 'June',\n 'July',\n 'August',\n 'September',\n 'October',\n 'November',\n 'December',\n ];\n\n /** Month name in the header: `locale` when set, the English names otherwise. */\n readonly currentMonthName = computed(() => {\n const locale = this.locale();\n return locale\n ? new Date(this.currentYear(), this.currentMonth(), 1).toLocaleDateString(locale, { month: 'long' })\n : this.monthNames[this.currentMonth()];\n });\n\n /** Weekday headers in grid order, starting at `firstDayOfWeek`. */\n readonly weekdayLabels = computed(() => {\n const locale = this.locale();\n const first = this.gridStart();\n // 1 Jan 2023 was a Sunday, so day d of that week has getDay() === d.\n const names = locale\n ? Array.from({ length: 7 }, (_, d) =>\n new Date(2023, 0, 1 + d).toLocaleDateString(locale, { weekday: 'short' }).replace(/\\.$/, ''),\n )\n : this.weekDays;\n return Array.from({ length: 7 }, (_, i) => names[(first + i) % 7]);\n });\n\n /** `firstDayOfWeek` clamped to 0–6. */\n private readonly gridStart = computed(() => {\n const day = Math.trunc(Number(this.firstDayOfWeek()));\n return Number.isFinite(day) ? ((day % 7) + 7) % 7 : 0;\n });\n\n /** id of the helper/error text the input is described by (aria-describedby) */\n readonly describedBy = computed(() => {\n if (this.error() && this.errorMessage()) {\n return `${this.inputId}-error`;\n }\n return this.helperText() ? `${this.inputId}-helper` : null;\n });\n\n /**\n * Computed classes for the datepicker input element\n */\n readonly datepickerClasses = computed(() => {\n const classes = [\n 'lc-datepicker',\n `lc-datepicker--${this.variant()}`,\n `lc-datepicker--${this.size()}`,\n ];\n\n if (this.isDisabled()) {\n classes.push('lc-datepicker--disabled');\n }\n\n if (this.error()) {\n classes.push('lc-datepicker--error');\n }\n\n if (this.readonly()) {\n classes.push('lc-datepicker--readonly');\n }\n\n if (this.isOpen()) {\n classes.push('lc-datepicker--open');\n }\n\n return classes.join(' ');\n });\n\n // Private properties\n private readonly document = inject(DOCUMENT);\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onChange: (value: Date | null) => void = () => {};\n // eslint-disable-next-line @typescript-eslint/no-empty-function\n private onTouched: () => void = () => {};\n\n // Public methods\n /**\n * Toggle calendar open/closed\n */\n toggle(): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n if (this.isOpen()) {\n this.close();\n } else {\n this.open();\n }\n }\n\n /**\n * Open calendar\n */\n open(): void {\n if (this.isDisabled() || this.readonly() || this.isOpen()) {\n return;\n }\n this.isOpen.set(true);\n\n // Set calendar to selected date's month/year or current\n const date = this.selectedDate();\n if (date) {\n this.showMonthOf(date);\n }\n\n this.opened.emit();\n }\n\n /**\n * Close calendar. Idempotent: the overlay's `detach` re-enters here after\n * `isOpen` flips, and that second call must not emit `closed` again.\n */\n close(): void {\n if (!this.isOpen()) {\n return;\n }\n // A day button inside the panel may hold focus; it is about to be removed,\n // so hand focus back to the input instead of letting it drop to <body>.\n this.restoreFocusFromPanel();\n this.isOpen.set(false);\n this.closed.emit();\n }\n\n /**\n * Select a date\n */\n selectDate(date: Date): void {\n if (this.isDisabled() || this.readonly() || this.isDateDisabled(date)) {\n return;\n }\n\n this.commitDate(date);\n this.close();\n }\n\n /**\n * Clear selected date\n */\n clear(): void {\n this.selectedDate.set(null);\n this.inputValue.set('');\n this.onChange(null);\n this.dateChange.emit(null);\n }\n\n /**\n * Check if a date is disabled\n */\n isDateDisabled(date: Date): boolean {\n // min/max are compared by calendar day: consumers typically pass `new Date()`\n // (which carries the current time) while calendar cells sit at midnight.\n const day = this.startOfDay(date);\n\n const min = this.minDate();\n if (min && day < this.startOfDay(min)) {\n return true;\n }\n\n const max = this.maxDate();\n if (max && day > this.startOfDay(max)) {\n return true;\n }\n\n // Check disabled dates\n if (this.disabledDates().some((d) => this.isSameDate(d, date))) {\n return true;\n }\n\n // Check weekends\n if (this.disableWeekends()) {\n const weekday = date.getDay();\n if (weekday === 0 || weekday === 6) {\n return true;\n }\n }\n\n return false;\n }\n\n /**\n * Check if date is today\n */\n isToday(date: Date): boolean {\n const today = new Date();\n return this.isSameDate(date, today);\n }\n\n /** Accessible name of a day button: the full date, plus `selectedAriaLabel` when selected. */\n protected dayAriaLabel(date: Date): string {\n const locale = this.locale();\n const name = locale\n ? date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' })\n : date.toDateString();\n return this.isSelectedDate(date) ? `${name}, ${this.selectedAriaLabel()}` : name;\n }\n\n /**\n * Check if date is selected\n */\n isSelectedDate(date: Date): boolean {\n const selected = this.selectedDate();\n return selected ? this.isSameDate(date, selected) : false;\n }\n\n /**\n * Generate calendar days for current month\n */\n generateCalendarDays(): Date[] {\n const year = this.currentYear();\n const month = this.currentMonth();\n\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n\n const days: Date[] = [];\n\n // Add previous month's days, so the first column is `firstDayOfWeek`.\n const leadingDays = (firstDay.getDay() - this.gridStart() + 7) % 7;\n for (let i = leadingDays - 1; i >= 0; i--) {\n const date = new Date(year, month, -i);\n days.push(date);\n }\n\n // Add current month's days\n for (let i = 1; i <= lastDay.getDate(); i++) {\n days.push(new Date(year, month, i));\n }\n\n // Add next month's days to complete the grid\n const remainingDays = 42 - days.length; // 6 weeks * 7 days\n for (let i = 1; i <= remainingDays; i++) {\n days.push(new Date(year, month + 1, i));\n }\n\n return days.slice(0, 42); // Ensure exactly 42 days (6 weeks)\n }\n\n /**\n * Navigate to next month\n */\n nextMonth(): void {\n if (this.currentMonth() === 11) {\n this.currentMonth.set(0);\n this.currentYear.set(this.currentYear() + 1);\n } else {\n this.currentMonth.set(this.currentMonth() + 1);\n }\n }\n\n /**\n * Navigate to previous month\n */\n previousMonth(): void {\n if (this.currentMonth() === 0) {\n this.currentMonth.set(11);\n this.currentYear.set(this.currentYear() - 1);\n } else {\n this.currentMonth.set(this.currentMonth() - 1);\n }\n }\n\n /**\n * Navigate to today\n */\n goToToday(): void {\n this.showMonthOf(new Date());\n }\n\n /**\n * Handle input change (manual date entry). Partial input is kept as text\n * only; the model changes once the text is a complete, valid, selectable date.\n */\n onInputChange(value: string): void {\n this.inputValue.set(value);\n\n if (value.trim() === '') {\n if (this.selectedDate() !== null) {\n this.clear();\n }\n return;\n }\n\n const date = this.parseDate(value, this.format());\n if (date && !this.isDateDisabled(date) && !this.isSelectedDate(date)) {\n this.commitDate(date);\n this.showMonthOf(date);\n }\n }\n\n /**\n * Handle keyboard navigation\n */\n onKeyDown(event: KeyboardEvent): void {\n if (this.isDisabled() || this.readonly()) {\n return;\n }\n\n if (\n !this.isOpen() &&\n (event.key === 'ArrowDown' || event.key === 'Enter' || event.key === ' ')\n ) {\n this.open();\n event.preventDefault();\n return;\n }\n\n if (!this.isOpen()) return;\n\n // While the text differs from the model the user is mid-edit: arrows must\n // move the caret, not the calendar selection.\n const editing = this.inputValue() !== this.formattedDate();\n const currentDate = this.selectedDate() || new Date();\n let newDate: Date | null = null;\n\n switch (event.key) {\n case 'Escape':\n this.close();\n event.preventDefault();\n // Only this datepicker should react; keep the key from reaching enclosing overlays.\n event.stopPropagation();\n break;\n\n case 'ArrowRight':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() + 1);\n event.preventDefault();\n break;\n\n case 'ArrowLeft':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() - 1);\n event.preventDefault();\n break;\n\n case 'ArrowDown':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() + 7);\n event.preventDefault();\n break;\n\n case 'ArrowUp':\n if (editing) break;\n newDate = new Date(currentDate);\n newDate.setDate(currentDate.getDate() - 7);\n event.preventDefault();\n break;\n\n case 'Enter': {\n const selected = this.selectedDate();\n if (selected) {\n this.selectDate(selected);\n }\n event.preventDefault();\n break;\n }\n }\n\n if (newDate && !this.isDateDisabled(newDate)) {\n this.selectedDate.set(newDate);\n this.showMonthOf(newDate);\n }\n }\n\n /**\n * Handle blur event: mark touched and drop any partial text that never became a date.\n */\n onBlur(): void {\n this.onTouched();\n this.inputValue.set(this.formattedDate());\n }\n\n /**\n * Handle click outside\n */\n onClickOutside(): void {\n this.close();\n }\n\n // ControlValueAccessor implementation\n writeValue(value: DateValue): void {\n let date: Date | null = null;\n if (value instanceof Date) {\n date = isNaN(value.getTime()) ? null : value;\n } else if (typeof value === 'string') {\n date = this.parseDate(value, this.format());\n }\n this.selectedDate.set(date);\n this.inputValue.set(this.formattedDate());\n }\n\n registerOnChange(fn: (value: Date | null) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n }\n\n /**\n * Check if date is in current month\n */\n isCurrentMonth(date: Date): boolean {\n return date.getMonth() === this.currentMonth() && date.getFullYear() === this.currentYear();\n }\n\n // Private helper methods\n private commitDate(date: Date): void {\n this.selectedDate.set(date);\n this.inputValue.set(this.formatDate(date, this.format()));\n this.onChange(date);\n this.dateChange.emit(date);\n }\n\n private showMonthOf(date: Date): void {\n this.currentMonth.set(date.getMonth());\n this.currentYear.set(date.getFullYear());\n }\n\n private restoreFocusFromPanel(): void {\n const panel = this.calendarPanel()?.nativeElement;\n const active = this.document.activeElement;\n if (panel && active && panel.contains(active)) {\n this.datepickerInput()?.nativeElement.focus();\n }\n }\n\n private startOfDay(date: Date): number {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate()).getTime();\n }\n\n /**\n * Check if two dates are the same day\n */\n private isSameDate(date1: Date, date2: Date): boolean {\n return (\n date1.getFullYear() === date2.getFullYear() &&\n date1.getMonth() === date2.getMonth() &&\n date1.getDate() === date2.getDate()\n );\n }\n\n private formatDate(date: Date, format: string): string {\n const year = date.getFullYear();\n const month = String(date.getMonth() + 1).padStart(2, '0');\n const day = String(date.getDate()).padStart(2, '0');\n\n return format.replace('YYYY', String(year)).replace('MM', month).replace('DD', day);\n }\n\n /**\n * Strict parse: the text must match the format's length, carry digits at the\n * YYYY/MM/DD positions and round-trip through formatDate (which rejects\n * things like month 13 or Feb 31 that `new Date` would silently roll over).\n * Returns null for partial or invalid input.\n */\n private parseDate(value: string, format: string): Date | null {\n if (value.length !== format.length) {\n return null;\n }\n\n const yearIndex = format.indexOf('YYYY');\n const monthIndex = format.indexOf('MM');\n const dayIndex = format.indexOf('DD');\n if (yearIndex < 0 || monthIndex < 0 || dayIndex < 0) {\n return null;\n }\n\n const yearText = value.substring(yearIndex, yearIndex + 4);\n const monthText = value.substring(monthIndex, monthIndex + 2);\n const dayText = value.substring(dayIndex, dayIndex + 2);\n if (!/^\\d{4}$/.test(yearText) || !/^\\d{2}$/.test(monthText) || !/^\\d{2}$/.test(dayText)) {\n return null;\n }\n\n const date = new Date(Number(yearText), Number(monthText) - 1, Number(dayText));\n return this.formatDate(date, format) === value ? date : null;\n }\n\n protected getInputValue(event: Event): string {\n return (event.target as HTMLInputElement).value;\n }\n}\n","<div class=\"lc-datepicker-wrapper\">\n <div class=\"lc-datepicker-input-wrapper\">\n <input\n #datepickerInput\n type=\"text\"\n [id]=\"inputId\"\n [class]=\"datepickerClasses()\"\n role=\"combobox\"\n aria-haspopup=\"dialog\"\n autocomplete=\"off\"\n [attr.aria-expanded]=\"isOpen() ? 'true' : 'false'\"\n [attr.aria-controls]=\"isOpen() ? inputId + '-calendar' : null\"\n [attr.aria-label]=\"ariaLabel() || null\"\n [attr.aria-required]=\"required() ? 'true' : null\"\n [attr.aria-disabled]=\"isDisabled() ? 'true' : null\"\n [attr.aria-invalid]=\"error() ? 'true' : null\"\n [attr.aria-describedby]=\"describedBy()\"\n [readonly]=\"readonly()\"\n [disabled]=\"isDisabled()\"\n [placeholder]=\"placeholder()\"\n [value]=\"inputValue()\"\n (input)=\"onInputChange(getInputValue($event))\"\n (click)=\"toggle()\"\n (keydown)=\"onKeyDown($event)\"\n (blur)=\"onBlur()\"\n />\n <div class=\"lc-datepicker-icons\">\n @if (selectedDate() && !isDisabled() && !readonly()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-clear\"\n (click)=\"clear(); $event.stopPropagation()\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M6.28 5.22a.75.75 0 00-1.06 1.06L8.94 10l-3.72 3.72a.75.75 0 101.06 1.06L10 11.06l3.72 3.72a.75.75 0 101.06-1.06L11.06 10l3.72-3.72a.75.75 0 00-1.06-1.06L10 8.94 6.28 5.22z\"\n />\n </svg>\n </button>\n }\n <svg\n class=\"lc-datepicker-calendar-icon\"\n xmlns=\"http://www.w3.org/2000/svg\"\n viewBox=\"0 0 20 20\"\n fill=\"currentColor\"\n aria-hidden=\"true\"\n >\n <path\n d=\"M5.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H6a.75.75 0 01-.75-.75V12zM6 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H6zM7.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H8a.75.75 0 01-.75-.75V12zM8 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H8zM9.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V10zM10 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H10zM9.25 14a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H10a.75.75 0 01-.75-.75V14zM12 9.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V10a.75.75 0 00-.75-.75H12zM11.25 12a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H12a.75.75 0 01-.75-.75V12zM12 13.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V14a.75.75 0 00-.75-.75H12zM13.25 10a.75.75 0 01.75-.75h.01a.75.75 0 01.75.75v.01a.75.75 0 01-.75.75H14a.75.75 0 01-.75-.75V10zM14 11.25a.75.75 0 00-.75.75v.01c0 .414.336.75.75.75h.01a.75.75 0 00.75-.75V12a.75.75 0 00-.75-.75H14z\"\n />\n <path\n fill-rule=\"evenodd\"\n d=\"M5.75 2a.75.75 0 01.75.75V4h7V2.75a.75.75 0 011.5 0V4h.25A2.75 2.75 0 0118 6.75v8.5A2.75 2.75 0 0115.25 18H4.75A2.75 2.75 0 012 15.25v-8.5A2.75 2.75 0 014.75 4H5V2.75A.75.75 0 015.75 2zm-1 5.5c-.69 0-1.25.56-1.25 1.25v6.5c0 .69.56 1.25 1.25 1.25h10.5c.69 0 1.25-.56 1.25-1.25v-6.5c0-.69-.56-1.25-1.25-1.25H4.75z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </div>\n </div>\n\n <!-- Calendar Panel -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"datepickerInput\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayHasBackdrop]=\"true\"\n [cdkConnectedOverlayBackdropClass]=\"'cdk-overlay-transparent-backdrop'\"\n (backdropClick)=\"onClickOutside()\"\n (detach)=\"close()\"\n >\n <div\n #calendarPanel\n class=\"lc-datepicker-calendar\"\n [class.lc-datepicker-calendar--open]=\"isOpen()\"\n [id]=\"inputId + '-calendar'\"\n role=\"dialog\"\n [attr.aria-label]=\"dialogAriaLabel()\"\n >\n <!-- Calendar Header -->\n <div class=\"lc-datepicker-header\">\n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"previousMonth()\"\n [attr.aria-label]=\"previousMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M12.79 5.23a.75.75 0 01-.02 1.06L8.832 10l3.938 3.71a.75.75 0 11-1.04 1.08l-4.5-4.25a.75.75 0 010-1.08l4.5-4.25a.75.75 0 011.06.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n \n <div class=\"lc-datepicker-month-year\" aria-live=\"polite\">\n {{ currentMonthName() }} {{ currentYear() }}\n </div>\n \n <button\n type=\"button\"\n class=\"lc-datepicker-nav-button\"\n (click)=\"nextMonth()\"\n [attr.aria-label]=\"nextMonthAriaLabel()\"\n >\n <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 20 20\" fill=\"currentColor\" aria-hidden=\"true\">\n <path\n fill-rule=\"evenodd\"\n d=\"M7.21 14.77a.75.75 0 01.02-1.06L11.168 10 7.23 6.29a.75.75 0 111.04-1.08l4.5 4.25a.75.75 0 010 1.08l-4.5 4.25a.75.75 0 01-1.06-.02z\"\n clip-rule=\"evenodd\"\n />\n </svg>\n </button>\n </div>\n\n <!-- Quick Actions -->\n <div class=\"lc-datepicker-quick-actions\">\n <button\n type=\"button\"\n class=\"lc-datepicker-today-button\"\n (click)=\"goToToday()\"\n >\n {{ todayLabel() }}\n </button>\n </div>\n\n <!-- Weekday Headers -->\n <div class=\"lc-datepicker-weekdays\" aria-hidden=\"true\">\n @for (day of weekdayLabels(); track $index) {\n <div class=\"lc-datepicker-weekday\">{{ day }}</div>\n }\n </div>\n\n <!-- Calendar Days -->\n <div class=\"lc-datepicker-days\">\n @for (date of generateCalendarDays(); track date.getTime()) {\n <button\n type=\"button\"\n class=\"lc-datepicker-day\"\n [class.lc-datepicker-day--other-month]=\"!isCurrentMonth(date)\"\n [class.lc-datepicker-day--today]=\"isToday(date)\"\n [class.lc-datepicker-day--selected]=\"isSelectedDate(date)\"\n [class.lc-datepicker-day--disabled]=\"isDateDisabled(date)\"\n [disabled]=\"isDateDisabled(date)\"\n [attr.aria-current]=\"isToday(date) ? 'date' : null\"\n [attr.aria-label]=\"dayAriaLabel(date)\"\n (click)=\"selectDate(date)\"\n >\n {{ date.getDate() }}\n </button>\n }\n </div>\n </div>\n </ng-template>\n\n <!-- Helper/Error Text -->\n @if (error() && errorMessage()) {\n <div class=\"lc-datepicker__error\" [id]=\"inputId + '-error'\" role=\"alert\">\n {{ errorMessage() }}\n </div>\n } @else if (helperText()) {\n <div class=\"lc-datepicker__helper\" [id]=\"inputId + '-helper'\">\n {{ helperText() }}\n </div>\n }\n</div>\n"],"mappings":"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"}