@lenne.tech/ng-base 22.0.2 → 22.0.5

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":"lenne.tech-ng-base-bug-bug-report-dialog-BRzVmKJr.mjs","names":["nextId"],"sources":["../../../projects/ng-base/bug/src/lib/ui/bug-attachments.ts","../../../projects/ng-base/bug/src/lib/ui/bug-attachments.html","../../../projects/ng-base/bug/src/lib/ui/bug-journey-timeline.ts","../../../projects/ng-base/bug/src/lib/ui/bug-journey-timeline.html","../../../projects/ng-base/bug/src/lib/ui/bug-report-dialog.ts","../../../projects/ng-base/bug/src/lib/ui/bug-report-dialog.html"],"sourcesContent":["import { Component, inject, input, output, signal } from '@angular/core';\nimport { LtI18nService } from '@lenne.tech/ng-base';\nimport { HlmBadgeImports, HlmButtonImports } from '@lenne.tech/ng-base/ui';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideFileText, lucidePaperclip, lucideUpload, lucideX } from '@ng-icons/lucide';\n\nimport type { LtBugAttachment } from '../bug-types';\nimport { formatLtBugFileSize } from '../report';\n\nlet nextId = 0;\n\n/**\n * Attachments of a bug report (the counterpart of `AttachmentsList.vue`): drop zone with a file button, list with\n * thumbnail, name, size, screenshot badge and a labelled remove button. Files are read as data URLs; files above\n * `maxFileSize` MB or beyond `maxFiles` are rejected with a message (`role=\"alert\"`).\n */\n@Component({\n selector: 'lt-bug-attachments',\n imports: [HlmBadgeImports, HlmButtonImports, NgIcon],\n providers: [provideIcons({ lucideFileText, lucidePaperclip, lucideUpload, lucideX })],\n templateUrl: './bug-attachments.html',\n host: { class: 'flex flex-col gap-3' },\n})\nexport class LtBugAttachments {\n /** `accept` of the file input (default as `@lenne.tech/bug.lt`). */\n readonly accept = input('image/*,.pdf,.doc,.docx,.txt,.log');\n readonly attachments = input.required<readonly LtBugAttachment[]>();\n readonly disabled = input(false);\n /** Maximum number of attachments including the screenshot (default 10, the server limit). */\n readonly maxFiles = input(10);\n /** Maximum file size in MB (default 10). */\n readonly maxFileSize = input(10);\n\n /** Files were read and accepted. */\n readonly added = output<LtBugAttachment[]>();\n /** The user removed an attachment (its id). */\n readonly removed = output<string>();\n\n protected readonly i18n = inject(LtI18nService);\n protected readonly hintId = `lt-bug-attachments-${nextId++}-hint`;\n protected readonly dragging = signal(false);\n protected readonly rejections = signal<string[]>([]);\n protected readonly formatSize = formatLtBugFileSize;\n private dragDepth = 0;\n\n protected openFileDialog(fileInput: HTMLInputElement): void {\n if (!this.disabled()) {\n fileInput.click();\n }\n }\n\n protected onInputChange(fileInput: HTMLInputElement): void {\n const files = Array.from(fileInput.files ?? []);\n fileInput.value = '';\n void this.addFiles(files);\n }\n\n protected onDragEnter(event: DragEvent): void {\n event.preventDefault();\n if (!this.disabled()) {\n this.dragDepth++;\n this.dragging.set(true);\n }\n }\n\n protected onDragOver(event: DragEvent): void {\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = this.disabled() ? 'none' : 'copy';\n }\n }\n\n protected onDragLeave(event: DragEvent): void {\n event.preventDefault();\n this.dragDepth = Math.max(0, this.dragDepth - 1);\n if (this.dragDepth === 0) {\n this.dragging.set(false);\n }\n }\n\n protected onDrop(event: DragEvent): void {\n event.preventDefault();\n this.dragDepth = 0;\n this.dragging.set(false);\n if (!this.disabled()) {\n void this.addFiles(Array.from(event.dataTransfer?.files ?? []));\n }\n }\n\n /** Read, validate and emit files; returns the accepted attachments. */\n async addFiles(files: File[]): Promise<LtBugAttachment[]> {\n if (!files.length) {\n return [];\n }\n const messages: string[] = [];\n const accepted: LtBugAttachment[] = [];\n const maxBytes = this.maxFileSize() * 1024 * 1024;\n let count = this.attachments().length;\n for (const file of files) {\n if (file.size > maxBytes) {\n messages.push(this.i18n.t('lt.bug.fileTooLarge', { max: this.maxFileSize(), name: file.name }));\n continue;\n }\n if (count >= this.maxFiles()) {\n messages.push(this.i18n.t('lt.bug.tooManyFiles', { max: this.maxFiles(), name: file.name }));\n continue;\n }\n try {\n const data = await readAsDataUrl(file);\n accepted.push({\n data,\n id: `attachment-${Date.now()}-${nextId++}`,\n name: file.name,\n size: file.size,\n type: file.type || 'application/octet-stream',\n ...(file.type.startsWith('image/') ? { preview: data } : {}),\n });\n count++;\n } catch {\n messages.push(this.i18n.t('lt.bug.fileReadFailed', { name: file.name }));\n }\n }\n this.rejections.set(messages);\n if (accepted.length) {\n this.added.emit(accepted);\n }\n return accepted;\n }\n\n protected removeLabel(attachment: LtBugAttachment): string {\n return this.i18n.t('lt.bug.removeAttachment', { name: attachment.name });\n }\n}\n\nfunction readAsDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => (typeof reader.result === 'string' ? resolve(reader.result) : reject(new Error('Unexpected FileReader result')));\n reader.onerror = () => reject(reader.error ?? new Error('FileReader error'));\n reader.onabort = () => reject(new Error('FileReader aborted'));\n reader.readAsDataURL(file);\n });\n}\n","<div\n class=\"border-border flex flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-4 text-center transition-colors data-[disabled=true]:opacity-50 data-[dragging=true]:border-primary data-[dragging=true]:bg-primary/5\"\n data-slot=\"dropzone\"\n [attr.data-dragging]=\"dragging() || null\"\n [attr.data-disabled]=\"disabled() || null\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <ng-icon name=\"lucideUpload\" class=\"text-muted-foreground text-2xl\" aria-hidden=\"true\" />\n <button hlmBtn type=\"button\" variant=\"outline\" size=\"sm\" [disabled]=\"disabled()\" [attr.aria-describedby]=\"hintId\" (click)=\"openFileDialog(fileInput)\">\n {{ i18n.t('lt.bug.selectFiles') }}\n </button>\n <p [id]=\"hintId\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.dropHint') }} · {{ i18n.t('lt.bug.maxFileSize', { max: maxFileSize() }) }}</p>\n <input\n #fileInput\n type=\"file\"\n multiple\n class=\"sr-only\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n data-slot=\"file-input\"\n [accept]=\"accept()\"\n [disabled]=\"disabled()\"\n (change)=\"onInputChange(fileInput)\"\n />\n</div>\n\n@if (rejections().length > 0) {\n <ul class=\"text-error flex flex-col gap-1 text-sm\" role=\"alert\" data-slot=\"rejections\">\n @for (message of rejections(); track $index) {\n <li>{{ message }}</li>\n }\n </ul>\n}\n\n@if (attachments().length > 0) {\n <div class=\"flex flex-col gap-2\">\n <p class=\"text-sm font-medium\" [id]=\"hintId + '-list'\">{{ i18n.t('lt.bug.attachmentsCount', { count: attachments().length }) }}</p>\n <ul class=\"flex flex-col gap-1\" data-slot=\"attachment-list\" [attr.aria-labelledby]=\"hintId + '-list'\">\n @for (attachment of attachments(); track attachment.id) {\n <li class=\"bg-muted/50 flex items-center gap-3 rounded-lg p-2\" data-slot=\"attachment\" [attr.data-screenshot]=\"attachment.isScreenshot || null\">\n @if (attachment.preview) {\n <img class=\"size-10 shrink-0 rounded object-cover\" [src]=\"attachment.preview\" [alt]=\"attachment.name\" />\n } @else {\n <ng-icon\n class=\"text-muted-foreground shrink-0 text-2xl\"\n aria-hidden=\"true\"\n [name]=\"attachment.type.startsWith('text/') || attachment.type.includes('pdf') ? 'lucideFileText' : 'lucidePaperclip'\"\n />\n }\n <div class=\"flex min-w-0 flex-1 flex-col\">\n <div class=\"flex min-w-0 items-center gap-2\">\n <span class=\"truncate text-sm font-medium\" [title]=\"attachment.name\">{{ attachment.name }}</span>\n @if (attachment.isScreenshot) {\n <span hlmBadge variant=\"secondary\">{{ i18n.t('lt.bug.screenshot') }}</span>\n }\n </div>\n <span class=\"text-muted-foreground text-xs\">{{ formatSize(attachment.size) }}</span>\n </div>\n <button\n hlmBtn\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n data-action=\"remove\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"removeLabel(attachment)\"\n (click)=\"removed.emit(attachment.id)\"\n >\n <ng-icon name=\"lucideX\" aria-hidden=\"true\" />\n </button>\n </li>\n }\n </ul>\n </div>\n}\n","import { Component, computed, inject, input, signal } from '@angular/core';\nimport { LtI18nService } from '@lenne.tech/ng-base';\nimport { HlmBadgeImports, HlmNativeSelectImports } from '@lenne.tech/ng-base/ui';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport {\n lucideAppWindow,\n lucideArrowUpDown,\n lucideCircleAlert,\n lucideCircleArrowRight,\n lucideClock,\n lucideFileText,\n lucideHand,\n lucideInfo,\n lucideKeyboard,\n lucideMousePointerClick,\n lucidePencil,\n lucideSend,\n lucideX,\n} from '@ng-icons/lucide';\n\nimport type { LtUserInteractionEvent } from '../bug-types';\n\nlet nextId = 0;\n\nconst ICONS: Record<string, string> = {\n click: 'lucideMousePointerClick',\n error: 'lucideCircleAlert',\n form_change: 'lucideFileText',\n form_submit: 'lucideSend',\n hover: 'lucideHand',\n input_change: 'lucidePencil',\n keyboard: 'lucideKeyboard',\n modal_close: 'lucideX',\n modal_open: 'lucideAppWindow',\n navigation: 'lucideCircleArrowRight',\n scroll: 'lucideArrowUpDown',\n};\n\nconst COLORS: Record<string, string> = {\n error: 'text-error',\n form_change: 'text-success',\n form_submit: 'text-success',\n input_change: 'text-warning',\n keyboard: 'text-info',\n modal_close: 'text-error',\n modal_open: 'text-info',\n navigation: 'text-info',\n};\n\n/**\n * User journey timeline (the counterpart of `UserJourneyTimeline.vue`): filter by event type, one row per event with\n * icon, type, time, target and details (text, value, URL, scroll position, key, error).\n */\n@Component({\n selector: 'lt-bug-journey-timeline',\n imports: [HlmBadgeImports, HlmNativeSelectImports, NgIcon],\n providers: [\n provideIcons({\n lucideAppWindow,\n lucideArrowUpDown,\n lucideCircleAlert,\n lucideCircleArrowRight,\n lucideClock,\n lucideFileText,\n lucideHand,\n lucideInfo,\n lucideKeyboard,\n lucideMousePointerClick,\n lucidePencil,\n lucideSend,\n lucideX,\n }),\n ],\n templateUrl: './bug-journey-timeline.html',\n host: { class: 'flex flex-col gap-3' },\n})\nexport class LtBugJourneyTimeline {\n readonly events = input.required<readonly LtUserInteractionEvent[]>();\n\n protected readonly i18n = inject(LtI18nService);\n protected readonly filterId = `lt-bug-journey-${nextId++}-filter`;\n protected readonly filter = signal('all');\n protected readonly types = computed(() => ['all', ...new Set(this.events().map((event) => event.type))]);\n protected readonly filtered = computed(() => {\n const filter = this.filter();\n return filter === 'all' ? this.events() : this.events().filter((event) => event.type === filter);\n });\n\n protected typeLabel(type: string): string {\n if (type === 'all') {\n return this.i18n.t('lt.bug.allEventTypes');\n }\n const key = `lt.bug.events.${type}`;\n const label = this.i18n.t(key);\n return label === key ? type.replace(/_/g, ' ').replace(/\\b\\w/g, (letter) => letter.toUpperCase()) : label;\n }\n\n protected icon(type: string): string {\n return ICONS[type] ?? 'lucideInfo';\n }\n\n protected color(type: string): string {\n return COLORS[type] ?? 'text-primary';\n }\n\n protected time(timestamp: string): string {\n const date = new Date(timestamp);\n return Number.isNaN(date.getTime()) ? '' : date.toLocaleTimeString(this.i18n.locale() === 'en' ? 'en-GB' : 'de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n }\n\n /** Details line (same order as `@lenne.tech/bug.lt`). */\n protected details(event: LtUserInteractionEvent): string {\n const metadata = event.metadata;\n if (!metadata) {\n return '';\n }\n const parts: string[] = [];\n if (metadata.text) {\n parts.push(`${this.i18n.t('lt.bug.metaText')}: ${metadata.text.length > 30 ? `${metadata.text.slice(0, 30)}…` : metadata.text}`);\n }\n if (metadata.value) {\n parts.push(`${this.i18n.t('lt.bug.metaValue')}: ${metadata.value}`);\n }\n if (metadata.url && metadata.url !== metadata.toUrl) {\n parts.push(`${this.i18n.t('lt.bug.metaUrl')}: ${metadata.url}`);\n }\n if (metadata.toUrl) {\n parts.push(`→ ${metadata.toUrl}`);\n }\n if (metadata.scrollPosition !== undefined) {\n parts.push(`${this.i18n.t('lt.bug.metaPosition')}: ${metadata.scrollPosition}px`);\n }\n if (metadata.key) {\n parts.push(`${this.i18n.t('lt.bug.metaKey')}: ${metadata.key}`);\n }\n if (metadata.errorMessage) {\n parts.push(`${this.i18n.t('lt.bug.metaError')}: ${metadata.errorMessage}`);\n }\n return parts.join(' | ');\n }\n}\n","<div class=\"flex flex-col gap-1.5\">\n <label class=\"text-sm font-medium\" [for]=\"filterId\">{{ i18n.t('lt.bug.journeyFilter') }}</label>\n <hlm-native-select size=\"sm\" [selectId]=\"filterId\" [value]=\"filter()\" (valueChange)=\"filter.set($event || 'all')\">\n @for (type of types(); track type) {\n <option hlmNativeSelectOption [value]=\"type\">{{ typeLabel(type) }}</option>\n }\n </hlm-native-select>\n</div>\n\n@if (filtered().length > 0) {\n <ol class=\"flex max-h-96 flex-col gap-2 overflow-y-auto\" data-slot=\"journey-list\" [attr.aria-label]=\"i18n.t('lt.bug.journeyEvents')\">\n @for (event of filtered(); track $index) {\n <li class=\"border-border flex items-start gap-3 rounded-lg border p-3\" data-slot=\"journey-event\" [attr.data-type]=\"event.type\">\n <ng-icon class=\"mt-0.5 shrink-0 text-lg\" aria-hidden=\"true\" [class]=\"color(event.type)\" [name]=\"icon(event.type)\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div class=\"flex items-center justify-between gap-2\">\n <span hlmBadge variant=\"outline\">{{ typeLabel(event.type) }}</span>\n <time class=\"text-muted-foreground text-xs\" [attr.datetime]=\"event.timestamp\">{{ time(event.timestamp) }}</time>\n </div>\n <p class=\"truncate text-sm font-medium\" [title]=\"event.target\">{{ event.target }}</p>\n @if (details(event); as text) {\n <p class=\"text-muted-foreground truncate text-xs\" [title]=\"text\">{{ text }}</p>\n }\n </div>\n </li>\n }\n </ol>\n} @else {\n <div class=\"text-muted-foreground flex flex-col items-center gap-2 py-8 text-center\" data-slot=\"journey-empty\">\n <ng-icon name=\"lucideClock\" class=\"text-4xl opacity-50\" aria-hidden=\"true\" />\n <p class=\"text-sm\">{{ i18n.t('lt.bug.journeyEmpty') }}</p>\n </div>\n}\n","import { afterNextRender, Component, computed, ElementRef, inject, Injector, signal } from '@angular/core';\nimport { disabled, form, FormField, maxLength, required, submit, type FieldTree } from '@angular/forms/signals';\nimport { LT_I18N_OPTIONS, LtI18nService } from '@lenne.tech/ng-base';\nimport {\n HlmButtonImports,\n HlmCollapsibleImports,\n HlmDialogImports,\n HlmSpinnerImports,\n HlmSwitchImports,\n HlmTextareaImports,\n injectLtOverlayRef,\n LtFormField,\n LtNotice,\n LtOverlayService,\n LtSelect,\n LtTextField,\n type LtOverlayRef,\n type LtSelectOption,\n} from '@lenne.tech/ng-base/ui';\nimport { ltFocusFirstInvalid } from '@lenne.tech/ng-base/utils';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideChevronDown, lucideX } from '@ng-icons/lucide';\n\nimport { LtBugReportService } from '../bug-report-service';\nimport type { LtBugAttachment, LtBugReportType, LtUserInteractionEvent } from '../bug-types';\nimport { registerLtBugMessages } from '../i18n/messages';\nimport { emptyLtBugReportForm, ltBugPrefillFromError, ltDataUrlSize, type LtBugReportFormValue, type LtBugReportIncludes } from '../report';\nimport { LtBugAttachments } from './bug-attachments';\nimport { LtBugJourneyTimeline } from './bug-journey-timeline';\n\nconst TYPES: readonly LtBugReportType[] = ['bug', 'feature', 'enhancement', 'other'];\n\n/**\n * Content of the bug report dialog (opened by `<lt-bug-report>` through {@link openLtBugReportDialog}): title, type,\n * description, expected behavior, steps, attachments with the screenshot, switches for the collected data and the user\n * journey preview. Signal Forms validation; a failed submit focuses the first invalid field. Loaded on first use.\n */\n@Component({\n selector: 'lt-bug-report-dialog',\n imports: [\n FormField,\n HlmButtonImports,\n HlmCollapsibleImports,\n HlmDialogImports,\n HlmSpinnerImports,\n HlmSwitchImports,\n HlmTextareaImports,\n LtBugAttachments,\n LtBugJourneyTimeline,\n LtFormField,\n LtNotice,\n LtSelect,\n LtTextField,\n NgIcon,\n ],\n providers: [provideIcons({ lucideChevronDown, lucideX })],\n templateUrl: './bug-report-dialog.html',\n host: { 'data-lt-bug-ui': '', class: 'grid min-w-0 gap-6' },\n})\nexport class LtBugReportDialog {\n protected readonly bug = inject(LtBugReportService);\n protected readonly i18n = registered(inject(LtI18nService), inject(LT_I18N_OPTIONS).messages);\n private readonly ref = injectLtOverlayRef<boolean>();\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n protected readonly model = signal<LtBugReportFormValue>(initialForm(this.bug.lastError()));\n protected readonly reportForm = form(this.model, (path) => {\n required(path.title, { message: this.i18n.t('lt.bug.titleRequired') });\n maxLength(path.title, 255);\n required(path.type, { message: this.i18n.t('lt.bug.typeRequired') });\n required(path.description, { message: this.i18n.t('lt.bug.descriptionRequired') });\n disabled(path, () => this.bug.isSubmitting());\n });\n\n protected readonly attachments = signal<LtBugAttachment[]>(initialAttachments(this.bug.screenshot()));\n protected readonly includes = signal<LtBugReportIncludes>({ browserInfo: true, consoleLogs: true, networkRequests: true, userJourney: true });\n protected readonly showAdditional = signal(false);\n protected readonly showJourney = signal(false);\n\n /** Snapshot of the collected data at opening time. */\n protected readonly journey: LtUserInteractionEvent[] = this.bug.getUserJourney();\n protected readonly consoleCount = this.bug.getConsoleLogs().length;\n protected readonly networkCount = this.bug.getNetworkRequests().length;\n\n protected readonly options = this.bug.options;\n protected readonly journeyEnabled = this.options.enableUserJourney && this.options.userJourney.enabled;\n protected readonly hasScreenshot = computed(() => this.attachments().some((attachment) => attachment.isScreenshot));\n protected readonly typeOptions = computed<LtSelectOption<LtBugReportType>[]>(() => TYPES.map((type) => ({ label: this.i18n.t(`lt.bug.types.${type}`), value: type })));\n protected readonly typeError = computed(() => fieldError(this.reportForm.type));\n protected readonly descriptionError = computed(() => fieldError(this.reportForm.description));\n\n protected setInclude(key: keyof LtBugReportIncludes, value: boolean): void {\n this.includes.update((current) => ({ ...current, [key]: value }));\n }\n\n protected addAttachments(added: LtBugAttachment[]): void {\n this.attachments.update((current) => [...current, ...added]);\n }\n\n protected removeAttachment(id: string): void {\n this.attachments.update((current) => current.filter((attachment) => attachment.id !== id));\n }\n\n protected cancel(): void {\n if (!this.bug.isSubmitting()) {\n this.ref.close(false);\n }\n }\n\n protected async onSubmit(event?: Event): Promise<void> {\n event?.preventDefault();\n if (this.bug.isSubmitting()) {\n return;\n }\n await submit(this.reportForm, {\n action: async () => {\n try {\n await this.bug.submit(await this.bug.buildReport(this.model(), this.attachments(), this.includes()));\n this.bug.reset();\n this.ref.close(true);\n } catch {\n // The error is shown in the dialog (and as a toast); the user can retry.\n }\n return undefined;\n },\n onInvalid: () => afterNextRender(() => ltFocusFirstInvalid(this.host.nativeElement, { offset: 0 }), { injector: this.injector }),\n });\n }\n}\n\n/**\n * Open the bug report dialog through `LtOverlayService` (focus trapped, Escape and backdrop close, focus returns to the\n * trigger). Resolves `true` after a sent report.\n */\nexport function openLtBugReportDialog(injector: Injector): LtOverlayRef<boolean> {\n return injector.get(LtOverlayService).open<boolean>(LtBugReportDialog, { contentClass: 'sm:max-w-2xl' });\n}\n\n/** Register the `lt.bug.*` texts (part of this lazy chunk) before the form schema reads its messages. */\nfunction registered(i18n: LtI18nService, appMessages: Parameters<typeof registerLtBugMessages>[1]): LtI18nService {\n registerLtBugMessages(i18n, appMessages);\n return i18n;\n}\n\nfunction initialForm(error: ReturnType<LtBugReportService['lastError']>): LtBugReportFormValue {\n return error ? { ...emptyLtBugReportForm(), ...ltBugPrefillFromError(error) } : emptyLtBugReportForm();\n}\n\nfunction initialAttachments(screenshot: string | null): LtBugAttachment[] {\n if (!screenshot) {\n return [];\n }\n return [\n { data: screenshot, id: `screenshot-${Date.now()}`, isScreenshot: true, name: 'screenshot.png', preview: screenshot, size: ltDataUrlSize(screenshot), type: 'image/png' },\n ];\n}\n\n/** First error message of a touched, invalid field. */\nfunction fieldError(field: FieldTree<unknown>): string | null {\n const state = field();\n return state.invalid() && state.touched() ? (state.errors().find((error) => !!error.message)?.message ?? null) : null;\n}\n","<div hlmDialogHeader>\n <h2 hlmDialogTitle>{{ i18n.t('lt.bug.dialogTitle') }}</h2>\n <p hlmDialogDescription>{{ i18n.t('lt.bug.dialogDescription') }}</p>\n</div>\n\n<form id=\"lt-bug-form\" class=\"flex min-w-0 flex-col gap-4\" novalidate data-slot=\"bug-report-form\" (submit)=\"onSubmit($event)\">\n @if (bug.error(); as message) {\n <lt-notice variant=\"error\" data-slot=\"bug-report-error\">\n <div class=\"flex items-start justify-between gap-3\">\n <span>{{ message }}</span>\n <button hlmBtn type=\"button\" variant=\"ghost\" size=\"icon-sm\" class=\"-my-1 shrink-0\" [attr.aria-label]=\"i18n.t('lt.bug.dismissError')\" (click)=\"bug.error.set(null)\">\n <ng-icon name=\"lucideX\" aria-hidden=\"true\" />\n </button>\n </div>\n </lt-notice>\n }\n\n <lt-text-field id=\"lt-bug-title\" [label]=\"i18n.t('lt.bug.title')\" [placeholder]=\"i18n.t('lt.bug.titlePlaceholder')\" [formField]=\"reportForm.title\" />\n\n <lt-form-field for=\"lt-bug-type\" [label]=\"i18n.t('lt.bug.type')\" [required]=\"true\" [error]=\"typeError()\">\n <lt-select id=\"lt-bug-type\" [options]=\"typeOptions()\" [placeholder]=\"i18n.t('lt.bug.typePlaceholder')\" [formField]=\"reportForm.type\" />\n </lt-form-field>\n\n <lt-form-field for=\"lt-bug-description\" [label]=\"i18n.t('lt.bug.description')\" [required]=\"true\" [error]=\"descriptionError()\">\n <textarea\n hlmTextarea\n id=\"lt-bug-description\"\n rows=\"4\"\n class=\"max-h-64\"\n [placeholder]=\"i18n.t('lt.bug.descriptionPlaceholder')\"\n [forceInvalid]=\"!!descriptionError()\"\n [formField]=\"reportForm.description\"\n ></textarea>\n </lt-form-field>\n\n <lt-form-field for=\"lt-bug-expected\" [label]=\"i18n.t('lt.bug.expectedBehavior')\">\n <textarea\n hlmTextarea\n id=\"lt-bug-expected\"\n rows=\"3\"\n class=\"max-h-48\"\n [placeholder]=\"i18n.t('lt.bug.expectedBehaviorPlaceholder')\"\n [formField]=\"reportForm.expectedBehavior\"\n ></textarea>\n </lt-form-field>\n\n <lt-form-field for=\"lt-bug-steps\" [label]=\"i18n.t('lt.bug.stepsToReproduce')\">\n <textarea\n hlmTextarea\n id=\"lt-bug-steps\"\n rows=\"3\"\n class=\"max-h-48\"\n [placeholder]=\"i18n.t('lt.bug.stepsToReproducePlaceholder')\"\n [formField]=\"reportForm.stepsToReproduce\"\n ></textarea>\n </lt-form-field>\n\n <section class=\"flex flex-col gap-2\" aria-labelledby=\"lt-bug-attachments-title\" data-slot=\"bug-report-attachments\">\n <h3 id=\"lt-bug-attachments-title\" class=\"text-sm font-medium\">\n {{ i18n.t('lt.bug.attachments') }}\n @if (hasScreenshot()) {\n <span class=\"text-muted-foreground ms-2 text-xs font-normal\">{{ i18n.t('lt.bug.screenshotCaptured') }}</span>\n }\n </h3>\n <lt-bug-attachments [attachments]=\"attachments()\" [disabled]=\"bug.isSubmitting()\" (added)=\"addAttachments($event)\" (removed)=\"removeAttachment($event)\" />\n </section>\n\n @if (options.enableBrowserInfo || options.enableConsoleLogs || options.enableNetworkRequests || journeyEnabled) {\n <div hlmCollapsible class=\"border-border rounded-lg border\" data-slot=\"bug-report-additional\" [expanded]=\"showAdditional()\" (expandedChange)=\"showAdditional.set($event)\">\n <button hlmCollapsibleTrigger type=\"button\" class=\"hover:bg-muted flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-start text-sm font-medium\">\n <span>{{ i18n.t('lt.bug.additionalInfo') }}</span>\n <ng-icon name=\"lucideChevronDown\" class=\"transition-transform duration-200\" aria-hidden=\"true\" [class.rotate-180]=\"showAdditional()\" />\n </button>\n <div hlmCollapsibleContent class=\"border-border flex flex-col gap-3 border-t p-3\">\n @if (options.enableBrowserInfo) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-browser-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.browserInfo') }}</span>\n <span id=\"lt-bug-include-browser-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.browserInfoHint') }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-browser\"\n aria-labelledby=\"lt-bug-include-browser-label\"\n aria-describedby=\"lt-bug-include-browser-hint\"\n [checked]=\"includes().browserInfo\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('browserInfo', $event)\"\n />\n </div>\n }\n @if (options.enableConsoleLogs) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-console-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.consoleLogs') }}</span>\n <span id=\"lt-bug-include-console-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.consoleLogsHint', { count: consoleCount }) }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-console\"\n aria-labelledby=\"lt-bug-include-console-label\"\n aria-describedby=\"lt-bug-include-console-hint\"\n [checked]=\"includes().consoleLogs\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('consoleLogs', $event)\"\n />\n </div>\n }\n @if (options.enableNetworkRequests) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-network-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.networkRequests') }}</span>\n <span id=\"lt-bug-include-network-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.networkRequestsHint', { count: networkCount }) }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-network\"\n aria-labelledby=\"lt-bug-include-network-label\"\n aria-describedby=\"lt-bug-include-network-hint\"\n [checked]=\"includes().networkRequests\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('networkRequests', $event)\"\n />\n </div>\n }\n @if (journeyEnabled) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-journey-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.userJourney') }}</span>\n <span id=\"lt-bug-include-journey-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.userJourneyHint', { count: journey.length }) }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-journey\"\n aria-labelledby=\"lt-bug-include-journey-label\"\n aria-describedby=\"lt-bug-include-journey-hint\"\n [checked]=\"includes().userJourney\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('userJourney', $event)\"\n />\n </div>\n }\n </div>\n </div>\n }\n\n @if (journeyEnabled && includes().userJourney && journey.length > 0) {\n <div hlmCollapsible class=\"border-border rounded-lg border\" data-slot=\"bug-report-journey\" [expanded]=\"showJourney()\" (expandedChange)=\"showJourney.set($event)\">\n <button hlmCollapsibleTrigger type=\"button\" class=\"hover:bg-muted flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-start text-sm font-medium\">\n <span>{{ i18n.t('lt.bug.journeyPreview', { count: journey.length }) }}</span>\n <ng-icon name=\"lucideChevronDown\" class=\"transition-transform duration-200\" aria-hidden=\"true\" [class.rotate-180]=\"showJourney()\" />\n </button>\n <div hlmCollapsibleContent class=\"border-border border-t p-3\">\n <lt-bug-journey-timeline [events]=\"journey\" />\n </div>\n </div>\n }\n</form>\n\n<div hlmDialogFooter>\n <button hlmBtn type=\"button\" variant=\"outline\" data-action=\"cancel\" [disabled]=\"bug.isSubmitting()\" (click)=\"cancel()\">{{ i18n.t('lt.bug.cancel') }}</button>\n <button hlmBtn type=\"submit\" form=\"lt-bug-form\" data-action=\"submit\" [attr.aria-busy]=\"bug.isSubmitting() || null\" [attr.aria-disabled]=\"bug.isSubmitting() || null\">\n @if (bug.isSubmitting()) {\n <hlm-spinner aria-hidden=\"true\" />\n {{ i18n.t('lt.bug.submitting') }}\n } @else {\n {{ i18n.t('lt.bug.submit') }}\n }\n </button>\n</div>\n"],"mappings":";;;;;;;;;;;;AASA,IAAIA,WAAS;AAcb,IAAa,mBAAb,MAAa,iBAAgB;CAElB,SAAS,MAAM,qCAAoC,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACnD,cAAc,MAAM,SAAsC,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAC1D,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEvB,WAAW,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEpB,cAAc,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGvB,QAAQ,OAAM;CAEd,UAAU,OAAM;CAEN,OAAO,OAAO,aAAa;CAC3B,SAAS,sBAAsB,WAAQ;CACvC,WAAW,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACxB,aAAa,OAAiB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CACjC,aAAa;CACxB,YAAY;CAEV,eAAe,WAA2B;EAClD,IAAI,CAAC,KAAK,SAAQ,GAChB,UAAU,MAAK;CAEnB;CAEU,cAAc,WAA2B;EACjD,MAAM,QAAQ,MAAM,KAAK,UAAU,SAAS,CAAA,CAAE;EAC9C,UAAU,QAAQ;EAClB,AAAK,KAAK,SAAS,KAAK;CAC1B;CAEU,YAAY,OAAgB;EACpC,MAAM,eAAc;EACpB,IAAI,CAAC,KAAK,SAAQ,GAAI;GACpB,KAAK;GACL,KAAK,SAAS,IAAI,IAAI;EACxB;CACF;CAEU,WAAW,OAAgB;EACnC,MAAM,eAAc;EACpB,IAAI,MAAM,cACR,MAAM,aAAa,aAAa,KAAK,SAAQ,IAAK,SAAS;CAE/D;CAEU,YAAY,OAAgB;EACpC,MAAM,eAAc;EACpB,KAAK,YAAY,KAAK,IAAI,GAAG,KAAK,YAAY,CAAC;EAC/C,IAAI,KAAK,cAAc,GACrB,KAAK,SAAS,IAAI,KAAK;CAE3B;CAEU,OAAO,OAAgB;EAC/B,MAAM,eAAc;EACpB,KAAK,YAAY;EACjB,KAAK,SAAS,IAAI,KAAK;EACvB,IAAI,CAAC,KAAK,SAAQ,GAChB,AAAK,KAAK,SAAS,MAAM,KAAK,MAAM,cAAc,SAAS,CAAA,CAAE,CAAC;CAElE;CAGA,MAAM,SAAS,OAAa;EAC1B,IAAI,CAAC,MAAM,QACT,OAAO,CAAA;EAET,MAAM,WAAqB,CAAA;EAC3B,MAAM,WAA8B,CAAA;EACpC,MAAM,WAAW,KAAK,YAAW,IAAK,OAAO;EAC7C,IAAI,QAAQ,KAAK,YAAW,CAAE,CAAC;EAC/B,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,KAAK,OAAO,UAAU;IACxB,SAAS,KAAK,KAAK,KAAK,EAAE,uBAAuB;KAAE,KAAK,KAAK,YAAW;KAAI,MAAM,KAAK;IAAI,CAAE,CAAC;IAC9F;GACF;GACA,IAAI,SAAS,KAAK,SAAQ,GAAI;IAC5B,SAAS,KAAK,KAAK,KAAK,EAAE,uBAAuB;KAAE,KAAK,KAAK,SAAQ;KAAI,MAAM,KAAK;IAAI,CAAE,CAAC;IAC3F;GACF;GACA,IAAI;IACF,MAAM,OAAO,MAAM,cAAc,IAAI;IACrC,SAAS,KAAK;KACZ;KACA,IAAI,cAAc,KAAK,IAAG,EAAE,GAAI;KAChC,MAAM,KAAK;KACX,MAAM,KAAK;KACX,MAAM,KAAK,QAAQ;KACnB,GAAI,KAAK,KAAK,WAAW,QAAQ,IAAI,EAAE,SAAS,KAAI,IAAK,CAAA;IAC1D,CAAA;IACD;GACF,QAAQ;IACN,SAAS,KAAK,KAAK,KAAK,EAAE,yBAAyB,EAAE,MAAM,KAAK,KAAI,CAAE,CAAC;GACzE;EACF;EACA,KAAK,WAAW,IAAI,QAAQ;EAC5B,IAAI,SAAS,QACX,KAAK,MAAM,KAAK,QAAQ;EAE1B,OAAO;CACT;CAEU,YAAY,YAA2B;EAC/C,OAAO,KAAK,KAAK,EAAE,2BAA2B,EAAE,MAAM,WAAW,KAAI,CAAE;CACzE;CA5GW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAgB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAhB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAgB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA;GAAA,OAAA;GAAA,SAAA;EAAA;EAAA,MAAA,EAAA,gBAAA,sBAAA;EAAA,WAJhB,CAAC,aAAa;GAAE;GAAgB;GAAiB;GAAc;EAAO,CAAE,CAAC;EAAC,UAAA;EAAA,UCnBvF;EA8EA,cAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,SAAA;IAAA,UAAA,CAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,WAAA,MAAA;IAAA,UAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MD5D+C;IAAM,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;EAAA;CAAA,CAAA;;AAKxC,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAgB,YAAA,CAAA;EAP5B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAoB,SACrB;IAAC;IAAiB;IAAkB;GAAM;GAAC,WACzC,CAAC,aAAa;IAAE;IAAgB;IAAiB;IAAc;GAAO,CAAE,CAAC;GAAC,MAE/E,EAAE,OAAO,sBAAqB;GAAE,UAAA;EAAA,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiHxC,SAAS,cAAc,MAAU;CAC/B,OAAO,IAAI,SAAS,SAAS,WAAU;EACrC,MAAM,SAAS,IAAI,WAAU;EAC7B,OAAO,eAAgB,OAAO,OAAO,WAAW,WAAW,QAAQ,OAAO,MAAM,IAAI,uBAAO,IAAI,MAAM,8BAA8B,CAAC;EACpI,OAAO,gBAAgB,OAAO,OAAO,yBAAS,IAAI,MAAM,kBAAkB,CAAC;EAC3E,OAAO,gBAAgB,uBAAO,IAAI,MAAM,oBAAoB,CAAC;EAC7D,OAAO,cAAc,IAAI;CAC3B,CAAC;AACH;AExHA,IAAI,SAAS;AAEb,MAAM,QAAgC;CACpC,OAAO;CACP,OAAO;CACP,aAAa;CACb,aAAa;CACb,OAAO;CACP,cAAc;CACd,UAAU;CACV,aAAa;CACb,YAAY;CACZ,YAAY;CACZ,QAAQ;AACT;AAED,MAAM,SAAiC;CACrC,OAAO;CACP,aAAa;CACb,aAAa;CACb,cAAc;CACd,UAAU;CACV,aAAa;CACb,YAAY;CACZ,YAAY;AACb;AA6BD,IAAa,uBAAb,MAAa,qBAAoB;CACtB,SAAS,MAAM,SAA6C,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAElD,OAAO,OAAO,aAAa;CAC3B,WAAW,kBAAkB,SAAQ;CACrC,SAAS,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACtB,QAAQ,eAAe,CAAC,OAAO,GAAG,IAAI,IAAI,KAAK,OAAM,CAAE,CAAC,KAAK,UAAU,MAAM,IAAI,CAAC,CAAC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACrF,WAAW,eAAc;EAC1C,MAAM,SAAS,KAAK,OAAM;EAC1B,OAAO,WAAW,QAAQ,KAAK,OAAM,IAAK,KAAK,OAAM,CAAE,CAAC,QAAQ,UAAU,MAAM,SAAS,MAAM;CACjG,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEQ,UAAU,MAAY;EAC9B,IAAI,SAAS,OACX,OAAO,KAAK,KAAK,EAAE,sBAAsB;EAE3C,MAAM,MAAM,iBAAiB;EAC7B,MAAM,QAAQ,KAAK,KAAK,EAAE,GAAG;EAC7B,OAAO,UAAU,MAAM,KAAK,QAAQ,MAAM,GAAG,CAAC,CAAC,QAAQ,UAAU,WAAW,OAAO,YAAW,CAAE,IAAI;CACtG;CAEU,KAAK,MAAY;EACzB,OAAO,MAAM,SAAS;CACxB;CAEU,MAAM,MAAY;EAC1B,OAAO,OAAO,SAAS;CACzB;CAEU,KAAK,WAAiB;EAC9B,MAAM,OAAO,IAAI,KAAK,SAAS;EAC/B,OAAO,OAAO,MAAM,KAAK,QAAO,CAAE,IAAI,KAAK,KAAK,mBAAmB,KAAK,KAAK,OAAM,MAAO,OAAO,UAAU,SAAS;GAAE,MAAM;GAAW,QAAQ;GAAW,QAAQ;EAAS,CAAE;CAC/K;CAGU,QAAQ,OAA6B;EAC7C,MAAM,WAAW,MAAM;EACvB,IAAI,CAAC,UACH,OAAO;EAET,MAAM,QAAkB,CAAA;EACxB,IAAI,SAAS,MACX,MAAM,KAAK,GAAG,KAAK,KAAK,EAAE,iBAAiB,EAAC,IAAK,SAAS,KAAK,SAAS,KAAK,GAAG,SAAS,KAAK,MAAM,GAAG,EAAE,EAAC,KAAM,SAAS,MAAM;EAEjI,IAAI,SAAS,OACX,MAAM,KAAK,GAAG,KAAK,KAAK,EAAE,kBAAkB,EAAC,IAAK,SAAS,OAAO;EAEpE,IAAI,SAAS,OAAO,SAAS,QAAQ,SAAS,OAC5C,MAAM,KAAK,GAAG,KAAK,KAAK,EAAE,gBAAgB,EAAC,IAAK,SAAS,KAAK;EAEhE,IAAI,SAAS,OACX,MAAM,KAAK,KAAK,SAAS,OAAO;EAElC,IAAI,SAAS,mBAAmB,QAC9B,MAAM,KAAK,GAAG,KAAK,KAAK,EAAE,qBAAqB,EAAC,IAAK,SAAS,eAAc,GAAI;EAElF,IAAI,SAAS,KACX,MAAM,KAAK,GAAG,KAAK,KAAK,EAAE,gBAAgB,EAAC,IAAK,SAAS,KAAK;EAEhE,IAAI,SAAS,cACX,MAAM,KAAK,GAAG,KAAK,KAAK,EAAE,kBAAkB,EAAC,IAAK,SAAS,cAAc;EAE3E,OAAO,MAAM,KAAK,KAAK;CACzB;CA/DW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAoB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAApB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAoB,cAAA;EAAA,UAAA;EAAA,QAAA,EAAA,QAAA;GAAA,mBAAA;GAAA,YAAA;GAAA,UAAA;GAAA,YAAA;GAAA,mBAAA;EAAA,EAAA;EAAA,MAAA,EAAA,gBAAA,sBAAA;EAAA,WApBpB,CACT,aAAa;GACX;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;GACA;EACD,CAAA,CACF;EAAA,UAAA;EAAA,UCxEH;EAiCA,cAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,SAAA;IAAA,UAAA,CAAA,UAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,aAAA;IAAA,UAAA,CAAA,iBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,uBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MDsBqD;IAAM,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;EAAA;CAAA,CAAA;;AAqB9C,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAoB,YAAA,CAAA;EAvBhC,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAyB,SAC1B;IAAC;IAAiB;IAAwB;GAAM;GAAC,WAC/C,CACT,aAAa;IACX;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD,CAAA,CACF;GAAA,MAEK,EAAE,OAAO,sBAAqB;GAAE,UAAA;EAAA,CAAA;;;;;;;;;;;AE5CxC,MAAM,QAAoC;CAAC;CAAO;CAAW;CAAe;AAAO;AA6BnF,IAAa,oBAAb,MAAa,kBAAiB;CACT,MAAM,OAAO,kBAAkB;CAC/B,OAAO,WAAW,OAAO,aAAa,GAAG,OAAO,eAAe,CAAC,CAAC,QAAQ;CAC3E,MAAM,mBAAkB;CACxB,OAAO,OAAgC,UAAU;CACjD,WAAW,OAAO,QAAQ;CAExB,QAAQ,OAA6B,YAAY,KAAK,IAAI,UAAS,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACvE,aAAa,KAAK,KAAK,QAAQ,SAAQ;EACxD,SAAS,KAAK,OAAO,EAAE,SAAS,KAAK,KAAK,EAAE,sBAAsB,EAAC,CAAE;EACrE,UAAU,KAAK,OAAO,GAAG;EACzB,SAAS,KAAK,MAAM,EAAE,SAAS,KAAK,KAAK,EAAE,qBAAqB,EAAC,CAAE;EACnE,SAAS,KAAK,aAAa,EAAE,SAAS,KAAK,KAAK,EAAE,4BAA4B,EAAC,CAAE;EACjF,SAAS,YAAY,KAAK,IAAI,aAAY,CAAE;CAC9C,CAAC;CAEkB,cAAc,OAA0B,mBAAmB,KAAK,IAAI,WAAU,CAAE,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAClF,WAAW,OAA4B;EAAE,aAAa;EAAM,aAAa;EAAM,iBAAiB;EAAM,aAAa;CAAI,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAC1H,iBAAiB,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAC9B,cAAc,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAG3B,UAAoC,KAAK,IAAI,eAAc;CAC3D,eAAe,KAAK,IAAI,eAAc,CAAE,CAAC;CACzC,eAAe,KAAK,IAAI,mBAAkB,CAAE,CAAC;CAE7C,UAAU,KAAK,IAAI;CACnB,iBAAiB,KAAK,QAAQ,qBAAqB,KAAK,QAAQ,YAAY;CAC5E,gBAAgB,eAAe,KAAK,YAAW,CAAE,CAAC,MAAM,eAAe,WAAW,YAAY,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAChG,cAAc,eAAkD,MAAM,KAAK,UAAU;EAAE,OAAO,KAAK,KAAK,EAAE,gBAAgB,MAAM;EAAG,OAAO;CAAI,EAAG,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACnJ,YAAY,eAAe,WAAW,KAAK,WAAW,IAAI,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAC5D,mBAAmB,eAAe,WAAW,KAAK,WAAW,WAAW,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAEnF,WAAW,KAAgC,OAAc;EACjE,KAAK,SAAS,QAAQ,aAAa;GAAE,GAAG;IAAU,MAAM;EAAK,EAAG;CAClE;CAEU,eAAe,OAAwB;EAC/C,KAAK,YAAY,QAAQ,YAAY,CAAC,GAAG,SAAS,GAAG,KAAK,CAAC;CAC7D;CAEU,iBAAiB,IAAU;EACnC,KAAK,YAAY,QAAQ,YAAY,QAAQ,QAAQ,eAAe,WAAW,OAAO,EAAE,CAAC;CAC3F;CAEU,SAAM;EACd,IAAI,CAAC,KAAK,IAAI,aAAY,GACxB,KAAK,IAAI,MAAM,KAAK;CAExB;CAEU,MAAM,SAAS,OAAa;EACpC,OAAO,eAAc;EACrB,IAAI,KAAK,IAAI,aAAY,GACvB;EAEF,MAAM,OAAO,KAAK,YAAY;GAC5B,QAAQ,YAAW;IACjB,IAAI;KACF,MAAM,KAAK,IAAI,OAAO,MAAM,KAAK,IAAI,YAAY,KAAK,MAAK,GAAI,KAAK,YAAW,GAAI,KAAK,SAAQ,CAAE,CAAC;KACnG,KAAK,IAAI,MAAK;KACd,KAAK,IAAI,MAAM,IAAI;IACrB,QAAQ,CAER;GAEF;GACA,iBAAiB,sBAAsB,oBAAoB,KAAK,KAAK,eAAe,EAAE,QAAQ,EAAC,CAAE,GAAG,EAAE,UAAU,KAAK,SAAQ,CAAE;EAChI,CAAA;CACH;CArEW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAiB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAjB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAiB,cAAA;EAAA,UAAA;EAAA,MAAA;GAAA,YAAA,EAAA,kBAAA,GAAA;GAAA,gBAAA;EAAA;EAAA,WAJjB,CAAC,aAAa;GAAE;GAAmB;EAAO,CAAE,CAAC;EAAC,UAAA;EAAA,UCvD3D;EAsKA,cAAA;GAAA;IAAA,MAAA;IAAA,MD9HI;IAAS,UAAA;IAAA,QAAA,CAAA,WAAA;IAAA,UAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,WAAA,MAAA;IAAA,UAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,uBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,uBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,sBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,iBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,iBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,gBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA,CAAA,QAAA,YAAA;IAAA,UAAA,CAAA,YAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,eAAA;IAAA,UAAA,CAAA,WAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,UAAA,CAAA,aAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAOT;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,SAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAChB;IAAoB,UAAA;IAAA,QAAA,CAAA,QAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACpB;IAAW,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACX;IAAQ,UAAA;IAAA,QAAA,CAAA,SAAA,SAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACR;IAAQ,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,eAAA,OAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACR;IAAW,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MACX;IAAM,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;EAAA;CAAA,CAAA;;AAMG,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAtB7B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAsB,SACvB;IACP;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;GACD;GAAA,WACU,CAAC,aAAa;IAAE;IAAmB;GAAO,CAAE,CAAC;GAAC,MAEnD;IAAE,kBAAkB;IAAI,OAAO;GAAoB;GAAE,UAAA;EAAA,CAAA;;;AA8E7D,SAAgB,sBAAsB,UAAkB;CACtD,OAAO,SAAS,IAAI,gBAAgB,CAAC,CAAC,KAAc,mBAAmB,EAAE,cAAc,eAAc,CAAE;AACzG;AAGA,SAAS,WAAW,MAAqB,aAAwD;CAC/F,sBAAsB,MAAM,WAAW;CACvC,OAAO;AACT;AAEA,SAAS,YAAY,OAAkD;CACrE,OAAO,QAAQ;EAAE,GAAG,qBAAoB;EAAI,GAAG,sBAAsB,KAAK;CAAC,IAAK,qBAAoB;AACtG;AAEA,SAAS,mBAAmB,YAAyB;CACnD,IAAI,CAAC,YACH,OAAO,CAAA;CAET,OAAO,CACL;EAAE,MAAM;EAAY,IAAI,cAAc,KAAK,IAAG;EAAM,cAAc;EAAM,MAAM;EAAkB,SAAS;EAAY,MAAM,cAAc,UAAU;EAAG,MAAM;CAAW,CACxK;AACH;AAGA,SAAS,WAAW,OAAyB;CAC3C,MAAM,QAAQ,MAAK;CACnB,OAAO,MAAM,QAAO,KAAM,MAAM,QAAO,IAAM,MAAM,OAAM,CAAE,CAAC,MAAM,UAAU,CAAC,CAAC,MAAM,OAAO,CAAC,EAAE,WAAW,OAAQ;AACnH"}
1
+ {"version":3,"file":"lenne.tech-ng-base-bug-bug-report-dialog-f6VNOWnW.mjs","names":["nextId"],"sources":["../../../projects/ng-base/bug/src/lib/ui/bug-attachments.ts","../../../projects/ng-base/bug/src/lib/ui/bug-attachments.html","../../../projects/ng-base/bug/src/lib/ui/bug-journey-timeline.ts","../../../projects/ng-base/bug/src/lib/ui/bug-journey-timeline.html","../../../projects/ng-base/bug/src/lib/ui/bug-report-dialog.ts","../../../projects/ng-base/bug/src/lib/ui/bug-report-dialog.html"],"sourcesContent":["import { Component, inject, input, output, signal } from '@angular/core';\nimport { LtI18nService } from '@lenne.tech/ng-base';\nimport { HlmBadgeImports, HlmButtonImports } from '@lenne.tech/ng-base/ui';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideFileText, lucidePaperclip, lucideUpload, lucideX } from '@ng-icons/lucide';\n\nimport type { LtBugAttachment } from '../bug-types';\nimport { formatLtBugFileSize } from '../report';\n\nlet nextId = 0;\n\n/**\n * Attachments of a bug report (the counterpart of `AttachmentsList.vue`): drop zone with a file button, list with\n * thumbnail, name, size, screenshot badge and a labelled remove button. Files are read as data URLs; files above\n * `maxFileSize` MB or beyond `maxFiles` are rejected with a message (`role=\"alert\"`).\n */\n@Component({\n selector: 'lt-bug-attachments',\n imports: [HlmBadgeImports, HlmButtonImports, NgIcon],\n providers: [provideIcons({ lucideFileText, lucidePaperclip, lucideUpload, lucideX })],\n templateUrl: './bug-attachments.html',\n host: { class: 'flex flex-col gap-3' },\n})\nexport class LtBugAttachments {\n /** `accept` of the file input (default as `@lenne.tech/bug.lt`). */\n readonly accept = input('image/*,.pdf,.doc,.docx,.txt,.log');\n readonly attachments = input.required<readonly LtBugAttachment[]>();\n readonly disabled = input(false);\n /** Maximum number of attachments including the screenshot (default 10, the server limit). */\n readonly maxFiles = input(10);\n /** Maximum file size in MB (default 10). */\n readonly maxFileSize = input(10);\n\n /** Files were read and accepted. */\n readonly added = output<LtBugAttachment[]>();\n /** The user removed an attachment (its id). */\n readonly removed = output<string>();\n\n protected readonly i18n = inject(LtI18nService);\n protected readonly hintId = `lt-bug-attachments-${nextId++}-hint`;\n protected readonly dragging = signal(false);\n protected readonly rejections = signal<string[]>([]);\n protected readonly formatSize = formatLtBugFileSize;\n private dragDepth = 0;\n\n protected openFileDialog(fileInput: HTMLInputElement): void {\n if (!this.disabled()) {\n fileInput.click();\n }\n }\n\n protected onInputChange(fileInput: HTMLInputElement): void {\n const files = Array.from(fileInput.files ?? []);\n fileInput.value = '';\n void this.addFiles(files);\n }\n\n protected onDragEnter(event: DragEvent): void {\n event.preventDefault();\n if (!this.disabled()) {\n this.dragDepth++;\n this.dragging.set(true);\n }\n }\n\n protected onDragOver(event: DragEvent): void {\n event.preventDefault();\n if (event.dataTransfer) {\n event.dataTransfer.dropEffect = this.disabled() ? 'none' : 'copy';\n }\n }\n\n protected onDragLeave(event: DragEvent): void {\n event.preventDefault();\n this.dragDepth = Math.max(0, this.dragDepth - 1);\n if (this.dragDepth === 0) {\n this.dragging.set(false);\n }\n }\n\n protected onDrop(event: DragEvent): void {\n event.preventDefault();\n this.dragDepth = 0;\n this.dragging.set(false);\n if (!this.disabled()) {\n void this.addFiles(Array.from(event.dataTransfer?.files ?? []));\n }\n }\n\n /** Read, validate and emit files; returns the accepted attachments. */\n async addFiles(files: File[]): Promise<LtBugAttachment[]> {\n if (!files.length) {\n return [];\n }\n const messages: string[] = [];\n const accepted: LtBugAttachment[] = [];\n const maxBytes = this.maxFileSize() * 1024 * 1024;\n let count = this.attachments().length;\n for (const file of files) {\n if (file.size > maxBytes) {\n messages.push(this.i18n.t('lt.bug.fileTooLarge', { max: this.maxFileSize(), name: file.name }));\n continue;\n }\n if (count >= this.maxFiles()) {\n messages.push(this.i18n.t('lt.bug.tooManyFiles', { max: this.maxFiles(), name: file.name }));\n continue;\n }\n try {\n const data = await readAsDataUrl(file);\n accepted.push({\n data,\n id: `attachment-${Date.now()}-${nextId++}`,\n name: file.name,\n size: file.size,\n type: file.type || 'application/octet-stream',\n ...(file.type.startsWith('image/') ? { preview: data } : {}),\n });\n count++;\n } catch {\n messages.push(this.i18n.t('lt.bug.fileReadFailed', { name: file.name }));\n }\n }\n this.rejections.set(messages);\n if (accepted.length) {\n this.added.emit(accepted);\n }\n return accepted;\n }\n\n protected removeLabel(attachment: LtBugAttachment): string {\n return this.i18n.t('lt.bug.removeAttachment', { name: attachment.name });\n }\n}\n\nfunction readAsDataUrl(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => (typeof reader.result === 'string' ? resolve(reader.result) : reject(new Error('Unexpected FileReader result')));\n reader.onerror = () => reject(reader.error ?? new Error('FileReader error'));\n reader.onabort = () => reject(new Error('FileReader aborted'));\n reader.readAsDataURL(file);\n });\n}\n","<div\n class=\"border-border flex flex-col items-center justify-center gap-2 rounded-lg border-2 border-dashed p-4 text-center transition-colors data-[disabled=true]:opacity-50 data-[dragging=true]:border-primary data-[dragging=true]:bg-primary/5\"\n data-slot=\"dropzone\"\n [attr.data-dragging]=\"dragging() || null\"\n [attr.data-disabled]=\"disabled() || null\"\n (dragenter)=\"onDragEnter($event)\"\n (dragover)=\"onDragOver($event)\"\n (dragleave)=\"onDragLeave($event)\"\n (drop)=\"onDrop($event)\"\n>\n <ng-icon name=\"lucideUpload\" class=\"text-muted-foreground text-2xl\" aria-hidden=\"true\" />\n <button hlmBtn type=\"button\" variant=\"outline\" size=\"sm\" [disabled]=\"disabled()\" [attr.aria-describedby]=\"hintId\" (click)=\"openFileDialog(fileInput)\">\n {{ i18n.t('lt.bug.selectFiles') }}\n </button>\n <p [id]=\"hintId\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.dropHint') }} · {{ i18n.t('lt.bug.maxFileSize', { max: maxFileSize() }) }}</p>\n <input\n #fileInput\n type=\"file\"\n multiple\n class=\"sr-only\"\n tabindex=\"-1\"\n aria-hidden=\"true\"\n data-slot=\"file-input\"\n [accept]=\"accept()\"\n [disabled]=\"disabled()\"\n (change)=\"onInputChange(fileInput)\"\n />\n</div>\n\n@if (rejections().length > 0) {\n <ul class=\"text-error flex flex-col gap-1 text-sm\" role=\"alert\" data-slot=\"rejections\">\n @for (message of rejections(); track $index) {\n <li>{{ message }}</li>\n }\n </ul>\n}\n\n@if (attachments().length > 0) {\n <div class=\"flex flex-col gap-2\">\n <p class=\"text-sm font-medium\" [id]=\"hintId + '-list'\">{{ i18n.t('lt.bug.attachmentsCount', { count: attachments().length }) }}</p>\n <ul class=\"flex flex-col gap-1\" data-slot=\"attachment-list\" [attr.aria-labelledby]=\"hintId + '-list'\">\n @for (attachment of attachments(); track attachment.id) {\n <li class=\"bg-muted/50 flex items-center gap-3 rounded-lg p-2\" data-slot=\"attachment\" [attr.data-screenshot]=\"attachment.isScreenshot || null\">\n @if (attachment.preview) {\n <img class=\"size-10 shrink-0 rounded object-cover\" [src]=\"attachment.preview\" [alt]=\"attachment.name\" />\n } @else {\n <ng-icon\n class=\"text-muted-foreground shrink-0 text-2xl\"\n aria-hidden=\"true\"\n [name]=\"attachment.type.startsWith('text/') || attachment.type.includes('pdf') ? 'lucideFileText' : 'lucidePaperclip'\"\n />\n }\n <div class=\"flex min-w-0 flex-1 flex-col\">\n <div class=\"flex min-w-0 items-center gap-2\">\n <span class=\"truncate text-sm font-medium\" [title]=\"attachment.name\">{{ attachment.name }}</span>\n @if (attachment.isScreenshot) {\n <span hlmBadge variant=\"secondary\">{{ i18n.t('lt.bug.screenshot') }}</span>\n }\n </div>\n <span class=\"text-muted-foreground text-xs\">{{ formatSize(attachment.size) }}</span>\n </div>\n <button\n hlmBtn\n type=\"button\"\n variant=\"ghost\"\n size=\"icon-sm\"\n data-action=\"remove\"\n [disabled]=\"disabled()\"\n [attr.aria-label]=\"removeLabel(attachment)\"\n (click)=\"removed.emit(attachment.id)\"\n >\n <ng-icon name=\"lucideX\" aria-hidden=\"true\" />\n </button>\n </li>\n }\n </ul>\n </div>\n}\n","import { Component, computed, inject, input, signal } from '@angular/core';\nimport { LtI18nService } from '@lenne.tech/ng-base';\nimport { HlmBadgeImports, HlmNativeSelectImports } from '@lenne.tech/ng-base/ui';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport {\n lucideAppWindow,\n lucideArrowUpDown,\n lucideCircleAlert,\n lucideCircleArrowRight,\n lucideClock,\n lucideFileText,\n lucideHand,\n lucideInfo,\n lucideKeyboard,\n lucideMousePointerClick,\n lucidePencil,\n lucideSend,\n lucideX,\n} from '@ng-icons/lucide';\n\nimport type { LtUserInteractionEvent } from '../bug-types';\n\nlet nextId = 0;\n\nconst ICONS: Record<string, string> = {\n click: 'lucideMousePointerClick',\n error: 'lucideCircleAlert',\n form_change: 'lucideFileText',\n form_submit: 'lucideSend',\n hover: 'lucideHand',\n input_change: 'lucidePencil',\n keyboard: 'lucideKeyboard',\n modal_close: 'lucideX',\n modal_open: 'lucideAppWindow',\n navigation: 'lucideCircleArrowRight',\n scroll: 'lucideArrowUpDown',\n};\n\nconst COLORS: Record<string, string> = {\n error: 'text-error',\n form_change: 'text-success',\n form_submit: 'text-success',\n input_change: 'text-warning',\n keyboard: 'text-info',\n modal_close: 'text-error',\n modal_open: 'text-info',\n navigation: 'text-info',\n};\n\n/**\n * User journey timeline (the counterpart of `UserJourneyTimeline.vue`): filter by event type, one row per event with\n * icon, type, time, target and details (text, value, URL, scroll position, key, error).\n */\n@Component({\n selector: 'lt-bug-journey-timeline',\n imports: [HlmBadgeImports, HlmNativeSelectImports, NgIcon],\n providers: [\n provideIcons({\n lucideAppWindow,\n lucideArrowUpDown,\n lucideCircleAlert,\n lucideCircleArrowRight,\n lucideClock,\n lucideFileText,\n lucideHand,\n lucideInfo,\n lucideKeyboard,\n lucideMousePointerClick,\n lucidePencil,\n lucideSend,\n lucideX,\n }),\n ],\n templateUrl: './bug-journey-timeline.html',\n host: { class: 'flex flex-col gap-3' },\n})\nexport class LtBugJourneyTimeline {\n readonly events = input.required<readonly LtUserInteractionEvent[]>();\n\n protected readonly i18n = inject(LtI18nService);\n protected readonly filterId = `lt-bug-journey-${nextId++}-filter`;\n protected readonly filter = signal('all');\n protected readonly types = computed(() => ['all', ...new Set(this.events().map((event) => event.type))]);\n protected readonly filtered = computed(() => {\n const filter = this.filter();\n return filter === 'all' ? this.events() : this.events().filter((event) => event.type === filter);\n });\n\n protected typeLabel(type: string): string {\n if (type === 'all') {\n return this.i18n.t('lt.bug.allEventTypes');\n }\n const key = `lt.bug.events.${type}`;\n const label = this.i18n.t(key);\n return label === key ? type.replace(/_/g, ' ').replace(/\\b\\w/g, (letter) => letter.toUpperCase()) : label;\n }\n\n protected icon(type: string): string {\n return ICONS[type] ?? 'lucideInfo';\n }\n\n protected color(type: string): string {\n return COLORS[type] ?? 'text-primary';\n }\n\n protected time(timestamp: string): string {\n const date = new Date(timestamp);\n return Number.isNaN(date.getTime()) ? '' : date.toLocaleTimeString(this.i18n.locale() === 'en' ? 'en-GB' : 'de-DE', { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n }\n\n /** Details line (same order as `@lenne.tech/bug.lt`). */\n protected details(event: LtUserInteractionEvent): string {\n const metadata = event.metadata;\n if (!metadata) {\n return '';\n }\n const parts: string[] = [];\n if (metadata.text) {\n parts.push(`${this.i18n.t('lt.bug.metaText')}: ${metadata.text.length > 30 ? `${metadata.text.slice(0, 30)}…` : metadata.text}`);\n }\n if (metadata.value) {\n parts.push(`${this.i18n.t('lt.bug.metaValue')}: ${metadata.value}`);\n }\n if (metadata.url && metadata.url !== metadata.toUrl) {\n parts.push(`${this.i18n.t('lt.bug.metaUrl')}: ${metadata.url}`);\n }\n if (metadata.toUrl) {\n parts.push(`→ ${metadata.toUrl}`);\n }\n if (metadata.scrollPosition !== undefined) {\n parts.push(`${this.i18n.t('lt.bug.metaPosition')}: ${metadata.scrollPosition}px`);\n }\n if (metadata.key) {\n parts.push(`${this.i18n.t('lt.bug.metaKey')}: ${metadata.key}`);\n }\n if (metadata.errorMessage) {\n parts.push(`${this.i18n.t('lt.bug.metaError')}: ${metadata.errorMessage}`);\n }\n return parts.join(' | ');\n }\n}\n","<div class=\"flex flex-col gap-1.5\">\n <label class=\"text-sm font-medium\" [for]=\"filterId\">{{ i18n.t('lt.bug.journeyFilter') }}</label>\n <hlm-native-select size=\"sm\" [selectId]=\"filterId\" [value]=\"filter()\" (valueChange)=\"filter.set($event || 'all')\">\n @for (type of types(); track type) {\n <option hlmNativeSelectOption [value]=\"type\">{{ typeLabel(type) }}</option>\n }\n </hlm-native-select>\n</div>\n\n@if (filtered().length > 0) {\n <ol class=\"flex max-h-96 flex-col gap-2 overflow-y-auto\" data-slot=\"journey-list\" [attr.aria-label]=\"i18n.t('lt.bug.journeyEvents')\">\n @for (event of filtered(); track $index) {\n <li class=\"border-border flex items-start gap-3 rounded-lg border p-3\" data-slot=\"journey-event\" [attr.data-type]=\"event.type\">\n <ng-icon class=\"mt-0.5 shrink-0 text-lg\" aria-hidden=\"true\" [class]=\"color(event.type)\" [name]=\"icon(event.type)\" />\n <div class=\"flex min-w-0 flex-1 flex-col gap-1\">\n <div class=\"flex items-center justify-between gap-2\">\n <span hlmBadge variant=\"outline\">{{ typeLabel(event.type) }}</span>\n <time class=\"text-muted-foreground text-xs\" [attr.datetime]=\"event.timestamp\">{{ time(event.timestamp) }}</time>\n </div>\n <p class=\"truncate text-sm font-medium\" [title]=\"event.target\">{{ event.target }}</p>\n @if (details(event); as text) {\n <p class=\"text-muted-foreground truncate text-xs\" [title]=\"text\">{{ text }}</p>\n }\n </div>\n </li>\n }\n </ol>\n} @else {\n <div class=\"text-muted-foreground flex flex-col items-center gap-2 py-8 text-center\" data-slot=\"journey-empty\">\n <ng-icon name=\"lucideClock\" class=\"text-4xl opacity-50\" aria-hidden=\"true\" />\n <p class=\"text-sm\">{{ i18n.t('lt.bug.journeyEmpty') }}</p>\n </div>\n}\n","import { afterNextRender, Component, computed, ElementRef, inject, Injector, signal } from '@angular/core';\nimport { disabled, form, FormField, maxLength, required, submit, type FieldTree } from '@angular/forms/signals';\nimport { LT_I18N_OPTIONS, LtI18nService } from '@lenne.tech/ng-base';\nimport {\n HlmButtonImports,\n HlmCollapsibleImports,\n HlmDialogImports,\n HlmSpinnerImports,\n HlmSwitchImports,\n HlmTextareaImports,\n injectLtOverlayRef,\n LtFormField,\n LtNotice,\n LtOverlayService,\n LtSelect,\n LtTextField,\n type LtOverlayRef,\n type LtSelectOption,\n} from '@lenne.tech/ng-base/ui';\nimport { ltFocusFirstInvalid } from '@lenne.tech/ng-base/utils';\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideChevronDown, lucideX } from '@ng-icons/lucide';\n\nimport { LtBugReportService } from '../bug-report-service';\nimport type { LtBugAttachment, LtBugReportType, LtUserInteractionEvent } from '../bug-types';\nimport { registerLtBugMessages } from '../i18n/messages';\nimport { emptyLtBugReportForm, ltBugPrefillFromError, ltDataUrlSize, type LtBugReportFormValue, type LtBugReportIncludes } from '../report';\nimport { LtBugAttachments } from './bug-attachments';\nimport { LtBugJourneyTimeline } from './bug-journey-timeline';\n\nconst TYPES: readonly LtBugReportType[] = ['bug', 'feature', 'enhancement', 'other'];\n\n/**\n * Content of the bug report dialog (opened by `<lt-bug-report>` through {@link openLtBugReportDialog}): title, type,\n * description, expected behavior, steps, attachments with the screenshot, switches for the collected data and the user\n * journey preview. Signal Forms validation; a failed submit focuses the first invalid field. Loaded on first use.\n */\n@Component({\n selector: 'lt-bug-report-dialog',\n imports: [\n FormField,\n HlmButtonImports,\n HlmCollapsibleImports,\n HlmDialogImports,\n HlmSpinnerImports,\n HlmSwitchImports,\n HlmTextareaImports,\n LtBugAttachments,\n LtBugJourneyTimeline,\n LtFormField,\n LtNotice,\n LtSelect,\n LtTextField,\n NgIcon,\n ],\n providers: [provideIcons({ lucideChevronDown, lucideX })],\n templateUrl: './bug-report-dialog.html',\n host: { 'data-lt-bug-ui': '', class: 'grid min-w-0 gap-6' },\n})\nexport class LtBugReportDialog {\n protected readonly bug = inject(LtBugReportService);\n protected readonly i18n = registered(inject(LtI18nService), inject(LT_I18N_OPTIONS).messages);\n private readonly ref = injectLtOverlayRef<boolean>();\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly injector = inject(Injector);\n\n protected readonly model = signal<LtBugReportFormValue>(initialForm(this.bug.lastError()));\n protected readonly reportForm = form(this.model, (path) => {\n required(path.title, { message: this.i18n.t('lt.bug.titleRequired') });\n maxLength(path.title, 255);\n required(path.type, { message: this.i18n.t('lt.bug.typeRequired') });\n required(path.description, { message: this.i18n.t('lt.bug.descriptionRequired') });\n disabled(path, () => this.bug.isSubmitting());\n });\n\n protected readonly attachments = signal<LtBugAttachment[]>(initialAttachments(this.bug.screenshot()));\n protected readonly includes = signal<LtBugReportIncludes>({ browserInfo: true, consoleLogs: true, networkRequests: true, userJourney: true });\n protected readonly showAdditional = signal(false);\n protected readonly showJourney = signal(false);\n\n /** Snapshot of the collected data at opening time. */\n protected readonly journey: LtUserInteractionEvent[] = this.bug.getUserJourney();\n protected readonly consoleCount = this.bug.getConsoleLogs().length;\n protected readonly networkCount = this.bug.getNetworkRequests().length;\n\n protected readonly options = this.bug.options;\n protected readonly journeyEnabled = this.options.enableUserJourney && this.options.userJourney.enabled;\n protected readonly hasScreenshot = computed(() => this.attachments().some((attachment) => attachment.isScreenshot));\n protected readonly typeOptions = computed<LtSelectOption<LtBugReportType>[]>(() => TYPES.map((type) => ({ label: this.i18n.t(`lt.bug.types.${type}`), value: type })));\n protected readonly typeError = computed(() => fieldError(this.reportForm.type));\n protected readonly descriptionError = computed(() => fieldError(this.reportForm.description));\n\n protected setInclude(key: keyof LtBugReportIncludes, value: boolean): void {\n this.includes.update((current) => ({ ...current, [key]: value }));\n }\n\n protected addAttachments(added: LtBugAttachment[]): void {\n this.attachments.update((current) => [...current, ...added]);\n }\n\n protected removeAttachment(id: string): void {\n this.attachments.update((current) => current.filter((attachment) => attachment.id !== id));\n }\n\n protected cancel(): void {\n if (!this.bug.isSubmitting()) {\n this.ref.close(false);\n }\n }\n\n protected async onSubmit(event?: Event): Promise<void> {\n event?.preventDefault();\n if (this.bug.isSubmitting()) {\n return;\n }\n await submit(this.reportForm, {\n action: async () => {\n try {\n await this.bug.submit(await this.bug.buildReport(this.model(), this.attachments(), this.includes()));\n this.bug.reset();\n this.ref.close(true);\n } catch {\n // The error is shown in the dialog (and as a toast); the user can retry.\n }\n return undefined;\n },\n onInvalid: () => afterNextRender(() => ltFocusFirstInvalid(this.host.nativeElement, { offset: 0 }), { injector: this.injector }),\n });\n }\n}\n\n/**\n * Open the bug report dialog through `LtOverlayService` (focus trapped, Escape and backdrop close, focus returns to the\n * trigger). Resolves `true` after a sent report.\n */\nexport function openLtBugReportDialog(injector: Injector): LtOverlayRef<boolean> {\n return injector.get(LtOverlayService).open<boolean>(LtBugReportDialog, { contentClass: 'sm:max-w-2xl' });\n}\n\n/** Register the `lt.bug.*` texts (part of this lazy chunk) before the form schema reads its messages. */\nfunction registered(i18n: LtI18nService, appMessages: Parameters<typeof registerLtBugMessages>[1]): LtI18nService {\n registerLtBugMessages(i18n, appMessages);\n return i18n;\n}\n\nfunction initialForm(error: ReturnType<LtBugReportService['lastError']>): LtBugReportFormValue {\n return error ? { ...emptyLtBugReportForm(), ...ltBugPrefillFromError(error) } : emptyLtBugReportForm();\n}\n\nfunction initialAttachments(screenshot: string | null): LtBugAttachment[] {\n if (!screenshot) {\n return [];\n }\n return [\n { data: screenshot, id: `screenshot-${Date.now()}`, isScreenshot: true, name: 'screenshot.png', preview: screenshot, size: ltDataUrlSize(screenshot), type: 'image/png' },\n ];\n}\n\n/** First error message of a touched, invalid field. */\nfunction fieldError(field: FieldTree<unknown>): string | null {\n const state = field();\n return state.invalid() && state.touched() ? (state.errors().find((error) => !!error.message)?.message ?? null) : null;\n}\n","<div hlmDialogHeader>\n <h2 hlmDialogTitle>{{ i18n.t('lt.bug.dialogTitle') }}</h2>\n <p hlmDialogDescription>{{ i18n.t('lt.bug.dialogDescription') }}</p>\n</div>\n\n<form id=\"lt-bug-form\" class=\"flex min-w-0 flex-col gap-4\" novalidate data-slot=\"bug-report-form\" (submit)=\"onSubmit($event)\">\n @if (bug.error(); as message) {\n <lt-notice variant=\"error\" data-slot=\"bug-report-error\">\n <div class=\"flex items-start justify-between gap-3\">\n <span>{{ message }}</span>\n <button hlmBtn type=\"button\" variant=\"ghost\" size=\"icon-sm\" class=\"-my-1 shrink-0\" [attr.aria-label]=\"i18n.t('lt.bug.dismissError')\" (click)=\"bug.error.set(null)\">\n <ng-icon name=\"lucideX\" aria-hidden=\"true\" />\n </button>\n </div>\n </lt-notice>\n }\n\n <lt-text-field id=\"lt-bug-title\" [label]=\"i18n.t('lt.bug.title')\" [placeholder]=\"i18n.t('lt.bug.titlePlaceholder')\" [formField]=\"reportForm.title\" />\n\n <lt-form-field for=\"lt-bug-type\" [label]=\"i18n.t('lt.bug.type')\" [required]=\"true\" [error]=\"typeError()\">\n <lt-select id=\"lt-bug-type\" [options]=\"typeOptions()\" [placeholder]=\"i18n.t('lt.bug.typePlaceholder')\" [formField]=\"reportForm.type\" />\n </lt-form-field>\n\n <lt-form-field for=\"lt-bug-description\" [label]=\"i18n.t('lt.bug.description')\" [required]=\"true\" [error]=\"descriptionError()\">\n <textarea\n hlmTextarea\n id=\"lt-bug-description\"\n rows=\"4\"\n class=\"max-h-64\"\n [placeholder]=\"i18n.t('lt.bug.descriptionPlaceholder')\"\n [forceInvalid]=\"!!descriptionError()\"\n [formField]=\"reportForm.description\"\n ></textarea>\n </lt-form-field>\n\n <lt-form-field for=\"lt-bug-expected\" [label]=\"i18n.t('lt.bug.expectedBehavior')\">\n <textarea\n hlmTextarea\n id=\"lt-bug-expected\"\n rows=\"3\"\n class=\"max-h-48\"\n [placeholder]=\"i18n.t('lt.bug.expectedBehaviorPlaceholder')\"\n [formField]=\"reportForm.expectedBehavior\"\n ></textarea>\n </lt-form-field>\n\n <lt-form-field for=\"lt-bug-steps\" [label]=\"i18n.t('lt.bug.stepsToReproduce')\">\n <textarea\n hlmTextarea\n id=\"lt-bug-steps\"\n rows=\"3\"\n class=\"max-h-48\"\n [placeholder]=\"i18n.t('lt.bug.stepsToReproducePlaceholder')\"\n [formField]=\"reportForm.stepsToReproduce\"\n ></textarea>\n </lt-form-field>\n\n <section class=\"flex flex-col gap-2\" aria-labelledby=\"lt-bug-attachments-title\" data-slot=\"bug-report-attachments\">\n <h3 id=\"lt-bug-attachments-title\" class=\"text-sm font-medium\">\n {{ i18n.t('lt.bug.attachments') }}\n @if (hasScreenshot()) {\n <span class=\"text-muted-foreground ms-2 text-xs font-normal\">{{ i18n.t('lt.bug.screenshotCaptured') }}</span>\n }\n </h3>\n <lt-bug-attachments [attachments]=\"attachments()\" [disabled]=\"bug.isSubmitting()\" (added)=\"addAttachments($event)\" (removed)=\"removeAttachment($event)\" />\n </section>\n\n @if (options.enableBrowserInfo || options.enableConsoleLogs || options.enableNetworkRequests || journeyEnabled) {\n <div hlmCollapsible class=\"border-border rounded-lg border\" data-slot=\"bug-report-additional\" [expanded]=\"showAdditional()\" (expandedChange)=\"showAdditional.set($event)\">\n <button hlmCollapsibleTrigger type=\"button\" class=\"hover:bg-muted flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-start text-sm font-medium\">\n <span>{{ i18n.t('lt.bug.additionalInfo') }}</span>\n <ng-icon name=\"lucideChevronDown\" class=\"transition-transform duration-200\" aria-hidden=\"true\" [class.rotate-180]=\"showAdditional()\" />\n </button>\n <div hlmCollapsibleContent class=\"border-border flex flex-col gap-3 border-t p-3\">\n @if (options.enableBrowserInfo) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-browser-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.browserInfo') }}</span>\n <span id=\"lt-bug-include-browser-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.browserInfoHint') }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-browser\"\n aria-labelledby=\"lt-bug-include-browser-label\"\n aria-describedby=\"lt-bug-include-browser-hint\"\n [checked]=\"includes().browserInfo\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('browserInfo', $event)\"\n />\n </div>\n }\n @if (options.enableConsoleLogs) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-console-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.consoleLogs') }}</span>\n <span id=\"lt-bug-include-console-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.consoleLogsHint', { count: consoleCount }) }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-console\"\n aria-labelledby=\"lt-bug-include-console-label\"\n aria-describedby=\"lt-bug-include-console-hint\"\n [checked]=\"includes().consoleLogs\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('consoleLogs', $event)\"\n />\n </div>\n }\n @if (options.enableNetworkRequests) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-network-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.networkRequests') }}</span>\n <span id=\"lt-bug-include-network-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.networkRequestsHint', { count: networkCount }) }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-network\"\n aria-labelledby=\"lt-bug-include-network-label\"\n aria-describedby=\"lt-bug-include-network-hint\"\n [checked]=\"includes().networkRequests\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('networkRequests', $event)\"\n />\n </div>\n }\n @if (journeyEnabled) {\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"flex min-w-0 flex-col\">\n <span id=\"lt-bug-include-journey-label\" class=\"text-sm font-medium\">{{ i18n.t('lt.bug.userJourney') }}</span>\n <span id=\"lt-bug-include-journey-hint\" class=\"text-muted-foreground text-xs\">{{ i18n.t('lt.bug.userJourneyHint', { count: journey.length }) }}</span>\n </div>\n <hlm-switch\n inputId=\"lt-bug-include-journey\"\n aria-labelledby=\"lt-bug-include-journey-label\"\n aria-describedby=\"lt-bug-include-journey-hint\"\n [checked]=\"includes().userJourney\"\n [disabled]=\"bug.isSubmitting()\"\n (checkedChange)=\"setInclude('userJourney', $event)\"\n />\n </div>\n }\n </div>\n </div>\n }\n\n @if (journeyEnabled && includes().userJourney && journey.length > 0) {\n <div hlmCollapsible class=\"border-border rounded-lg border\" data-slot=\"bug-report-journey\" [expanded]=\"showJourney()\" (expandedChange)=\"showJourney.set($event)\">\n <button hlmCollapsibleTrigger type=\"button\" class=\"hover:bg-muted flex w-full items-center justify-between rounded-lg px-3 py-2.5 text-start text-sm font-medium\">\n <span>{{ i18n.t('lt.bug.journeyPreview', { count: journey.length }) }}</span>\n <ng-icon name=\"lucideChevronDown\" class=\"transition-transform duration-200\" aria-hidden=\"true\" [class.rotate-180]=\"showJourney()\" />\n </button>\n <div hlmCollapsibleContent class=\"border-border border-t p-3\">\n <lt-bug-journey-timeline [events]=\"journey\" />\n </div>\n </div>\n }\n</form>\n\n<div hlmDialogFooter>\n <button hlmBtn type=\"button\" variant=\"outline\" data-action=\"cancel\" [disabled]=\"bug.isSubmitting()\" (click)=\"cancel()\">{{ i18n.t('lt.bug.cancel') }}</button>\n <button hlmBtn type=\"submit\" form=\"lt-bug-form\" data-action=\"submit\" [attr.aria-busy]=\"bug.isSubmitting() || null\" [attr.aria-disabled]=\"bug.isSubmitting() || null\">\n @if (bug.isSubmitting()) {\n <hlm-spinner aria-hidden=\"true\" />\n {{ i18n.t('lt.bug.submitting') }}\n } @else {\n {{ i18n.t('lt.bug.submit') }}\n }\n </button>\n</div>\n"],"mappings":"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"}
@@ -325,7 +325,7 @@ var LtBugReportService = class LtBugReportService {
325
325
  }
326
326
  static ɵfac = i0.ɵɵngDeclareFactory({
327
327
  minVersion: "12.0.0",
328
- version: "22.2.4",
328
+ version: "22.2.5",
329
329
  ngImport: i0,
330
330
  type: LtBugReportService,
331
331
  deps: [],
@@ -333,14 +333,14 @@ var LtBugReportService = class LtBugReportService {
333
333
  });
334
334
  static ɵprov = i0.ɵɵngDeclareService({
335
335
  minVersion: "22.0.0",
336
- version: "22.2.4",
336
+ version: "22.2.5",
337
337
  ngImport: i0,
338
338
  type: LtBugReportService
339
339
  });
340
340
  };
341
341
  i0.ɵɵngDeclareClassMetadata({
342
342
  minVersion: "12.0.0",
343
- version: "22.2.4",
343
+ version: "22.2.5",
344
344
  ngImport: i0,
345
345
  type: LtBugReportService,
346
346
  decorators: [{ type: Service }],
@@ -348,4 +348,4 @@ i0.ɵɵngDeclareClassMetadata({
348
348
  });
349
349
  export { LT_BUG_DEFAULTS as a, resolveLtBugOptions as c, registerLtBugEagerMessages as i, LtBugSubmitError as n, LT_BUG_DEFAULT_ENDPOINT as o, LT_BUG_SCREENSHOT_LOADER as r, LT_BUG_OPTIONS as s, LtBugReportService as t };
350
350
 
351
- //# sourceMappingURL=lenne.tech-ng-base-bug-bug-report-service-DWoTb_iw.mjs.map
351
+ //# sourceMappingURL=lenne.tech-ng-base-bug-bug-report-service-D6slR3GD.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"lenne.tech-ng-base-bug-bug-report-service-DWoTb_iw.mjs","names":["LT_BUG_INPUT_OPTIONS"],"sources":["../../../projects/ng-base/bug/src/lib/bug-options.ts","../../../projects/ng-base/bug/src/lib/i18n/load.ts","../../../projects/ng-base/bug/src/lib/screenshot.ts","../../../projects/ng-base/bug/src/lib/bug-report-service.ts"],"sourcesContent":["import { inject, InjectionToken } from '@angular/core';\nimport { LT_RUNTIME_CONFIG, mergeLtFeatureOptions } from '@lenne.tech/ng-base';\nimport { LT_BUG_INPUT_OPTIONS, type LtBugOptions, type LtResolvedBugOptions } from '@lenne.tech/ng-base/bug/provide';\n\n/** The runtime decision lives in `@lenne.tech/ng-base/bug/provide` (light entry for `app.config.ts` and the shell). */\nexport { isLtBugActive, LT_BUG_ACTIVE, LT_BUG_DEV_MODE, LT_BUG_INPUT_OPTIONS } from '@lenne.tech/ng-base/bug/provide';\n\n/** Default endpoint, the same as `@lenne.tech/bug.lt` (outside `/api`, so an API proxy does not swallow it). */\nexport const LT_BUG_DEFAULT_ENDPOINT = '/_bug-lt/report';\n\n/** Defaults of {@link LtBugOptions} (the module defaults of `@lenne.tech/bug.lt` 1.6.9, except the button color). */\nexport const LT_BUG_DEFAULTS: LtResolvedBugOptions = {\n autoOpenOnError: false,\n autoShow: true,\n // bug.lt: #ef4444; white text on it has 3.8:1 contrast (WCAG AA needs 4.5:1), red-600 has 4.8:1.\n buttonColor: '#dc2626',\n enableBrowserInfo: true,\n enableConsoleLogs: true,\n enableErrorBoundary: true,\n enableNetworkRequests: true,\n enableScreenshot: true,\n enableUserJourney: true,\n endpoint: LT_BUG_DEFAULT_ENDPOINT,\n maxConsoleLogs: 50,\n maxNetworkRequests: 50,\n position: 'bottom-right',\n theme: 'auto',\n userJourney: {\n captureClicks: true,\n captureErrors: true,\n captureFormInteractions: true,\n captureHover: false,\n captureInputChanges: false,\n captureInputValues: false,\n captureKeyboard: true,\n captureModalEvents: true,\n captureNavigation: true,\n captureScroll: false,\n enabled: true,\n maxEvents: 50,\n throttleRate: 100,\n },\n};\n\n/** Resolved options: defaults ← `provideLtBug(options)` ← runtime `lt.bug` (`LT_RUNTIME_CONFIG`). */\nexport const LT_BUG_OPTIONS = new InjectionToken<LtResolvedBugOptions>('LT_BUG_OPTIONS', {\n factory: () => resolveLtBugOptions(inject(LT_BUG_INPUT_OPTIONS) ?? {}, inject(LT_RUNTIME_CONFIG, { optional: true })?.lt?.['bug']),\n});\n\n/** Merge options onto the defaults; `userJourney` is merged per key, `undefined` never overrides, sizes are clamped. */\nexport function resolveLtBugOptions(...overrides: (LtBugOptions | Record<string, unknown> | null | undefined)[]): LtResolvedBugOptions {\n const merged = mergeLtFeatureOptions<LtResolvedBugOptions>(LT_BUG_DEFAULTS, ...overrides);\n return {\n ...merged,\n endpoint: typeof merged.endpoint === 'string' && merged.endpoint.startsWith('/') ? merged.endpoint : LT_BUG_DEFAULT_ENDPOINT,\n maxConsoleLogs: clampSize(merged.maxConsoleLogs, LT_BUG_DEFAULTS.maxConsoleLogs),\n maxNetworkRequests: clampSize(merged.maxNetworkRequests, LT_BUG_DEFAULTS.maxNetworkRequests),\n userJourney: {\n ...merged.userJourney,\n maxEvents: clampSize(merged.userJourney.maxEvents, LT_BUG_DEFAULTS.userJourney.maxEvents),\n throttleRate: Math.max(0, Number(merged.userJourney.throttleRate) || 0),\n },\n };\n}\n\n/** Ring buffer sizes are whole numbers between 1 and 1000. */\nfunction clampSize(value: unknown, fallback: number): number {\n const number = Math.floor(Number(value));\n return Number.isFinite(number) && number > 0 ? Math.min(number, 1000) : fallback;\n}\n","import type { LtI18nMessages, LtI18nService } from '@lenne.tech/ng-base';\n\n/**\n * The only texts needed before the dialog chunk is loaded: the floating button's label and its busy text. Kept equal to\n * `de.json` / `en.json` (checked by `i18n.spec.ts`).\n */\nexport const LT_BUG_EAGER_MESSAGES: Readonly<Record<'de' | 'en', LtI18nMessages>> = {\n de: { lt: { bug: { button: 'Fehler melden', capturing: 'Screenshot wird erstellt …' } } },\n en: { lt: { bug: { button: 'Report a bug', capturing: 'Taking screenshot …' } } },\n};\n\nconst loaded = new WeakSet<LtI18nService>();\nlet messagesModule: Promise<typeof import('./messages')> | null = null;\n\n/** Register the button texts (synchronously; texts the app configured keep priority). */\nexport function registerLtBugEagerMessages(i18n: LtI18nService, appMessages: Record<string, LtI18nMessages> = {}): void {\n for (const [locale, messages] of Object.entries(LT_BUG_EAGER_MESSAGES)) {\n const app = appMessages[locale];\n i18n.registerMessages(locale, app ? withAppTexts(messages, app) : messages);\n }\n}\n\n/** Load (lazy chunk) and register every `lt.bug.*` text once per `LtI18nService` instance. */\nexport async function loadLtBugMessages(i18n: LtI18nService, appMessages: Record<string, LtI18nMessages> = {}): Promise<void> {\n if (loaded.has(i18n)) {\n return;\n }\n messagesModule ??= import('./messages');\n try {\n (await messagesModule).registerLtBugMessages(i18n, appMessages);\n loaded.add(i18n);\n } catch {\n // Chunk failed to load: keep the keys, retry on the next call.\n messagesModule = null;\n }\n}\n\nfunction withAppTexts(base: LtI18nMessages, app: LtI18nMessages): LtI18nMessages {\n const result: LtI18nMessages = { ...base };\n for (const [key, value] of Object.entries(app)) {\n const current = result[key];\n if (current === undefined) {\n continue;\n }\n result[key] = typeof value === 'object' && typeof current === 'object' ? withAppTexts(current, value) : value;\n }\n return result;\n}\n","import { InjectionToken } from '@angular/core';\n\nimport type { LtBugTheme } from './bug-types';\nimport { LT_BUG_UI_ATTRIBUTE } from './constants';\n\n/** The part of `modern-screenshot` the reporter uses (structural, so the peer stays optional). */\nexport interface LtScreenshotLibrary {\n domToPng(node: Node, options?: Record<string, unknown>): Promise<string>;\n}\n\nlet library: Promise<LtScreenshotLibrary | null> | null = null;\n\n/** Load the optional peer `modern-screenshot` once; resolves `null` when it is not installed. */\nexport function loadLtScreenshotLibrary(): Promise<LtScreenshotLibrary | null> {\n library ??= import('modern-screenshot').then(\n (module) => {\n const candidate = module as unknown as Partial<LtScreenshotLibrary> & { default?: Partial<LtScreenshotLibrary> };\n const resolved = typeof candidate.domToPng === 'function' ? candidate : candidate.default;\n return typeof resolved?.domToPng === 'function' ? (resolved as LtScreenshotLibrary) : null;\n },\n () => null,\n );\n return library;\n}\n\n/**\n * Loader of the screenshot library (default: lazy `import('modern-screenshot')`, `null` when the optional peer is\n * missing: the screenshot feature is then hidden). Replace it in tests.\n */\nexport const LT_BUG_SCREENSHOT_LOADER = new InjectionToken<() => Promise<LtScreenshotLibrary | null>>('LT_BUG_SCREENSHOT_LOADER', {\n factory: () => loadLtScreenshotLibrary,\n});\n\n/**\n * PNG data URL of the visible viewport (current scroll position, device pixel ratio up to 2), without the reporter's\n * own UI. The background follows `theme` (`auto`: `html.dark` / `html.light`, then `color-scheme`, then the system).\n */\nexport function captureLtBugScreenshot(lib: LtScreenshotLibrary, view: Window, theme: LtBugTheme): Promise<string> {\n const doc = view.document;\n const dark = theme === 'dark' || (theme === 'auto' && isLtDarkColorMode(view));\n return lib.domToPng(doc.documentElement, {\n backgroundColor: dark ? '#0a0a0a' : '#ffffff',\n features: { restoreScrollPosition: true },\n fetch: { bypassingCache: true, requestInit: { mode: 'cors' } },\n filter: (node: Node) => !(node.nodeType === 1 && (node as Element).hasAttribute?.(LT_BUG_UI_ATTRIBUTE)),\n height: view.innerHeight,\n scale: Math.min(view.devicePixelRatio || 1, 2),\n style: { transform: 'none', transformOrigin: 'top left' },\n width: view.innerWidth,\n });\n}\n\n/** Whether the page currently renders dark (`html.dark`, `html.light`, computed `color-scheme`, system preference). */\nexport function isLtDarkColorMode(view: Window): boolean {\n const root = view.document?.documentElement;\n if (root?.classList.contains('dark')) {\n return true;\n }\n if (root?.classList.contains('light')) {\n return false;\n }\n const scheme = root && typeof view.getComputedStyle === 'function' ? view.getComputedStyle(root).colorScheme : '';\n if (scheme === 'dark' || scheme === 'light') {\n return scheme === 'dark';\n }\n return !!view.matchMedia?.('(prefers-color-scheme: dark)').matches;\n}\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, ErrorHandler, inject, Injector, PLATFORM_ID, Service, signal } from '@angular/core';\nimport { Router, ROUTES } from '@angular/router';\nimport { LT_I18N_OPTIONS, LT_RUNTIME_CONFIG, LtI18nService, LtToastService } from '@lenne.tech/ng-base';\n\nimport { isLtBugActive, LT_BUG_DEV_MODE, LT_BUG_INPUT_OPTIONS, LT_BUG_OPTIONS } from './bug-options';\nimport type {\n LtBrowserInfo,\n LtBugAttachment,\n LtBugErrorInfo,\n LtBugReportData,\n LtBugReportResponse,\n LtConsoleLogEntry,\n LtNetworkRequestEntry,\n LtUserInteractionEvent,\n LtUserInteractionMetadata,\n LtUserInteractionType,\n} from './bug-types';\nimport type { LtBugCaptureEngine } from './capture-engine';\nimport { loadLtBugMessages } from './i18n/load';\nimport type { LtBugReportFormValue, LtBugReportIncludes } from './report';\nimport { captureLtBugScreenshot, LT_BUG_SCREENSHOT_LOADER } from './screenshot';\n\n/** Error of {@link LtBugReportService.submit}; `message` is the translated text shown to the user. */\nexport class LtBugSubmitError extends Error {\n constructor(\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = 'LtBugSubmitError';\n }\n}\n\n/**\n * State and actions of the bug reporter, the counterpart of `useBugReport()` of `@lenne.tech/bug.lt`.\n *\n * `<lt-bug-report>` calls {@link start} when it is created: when the reporter is {@link active} it loads the capture engine\n * (a chunk of its own) and installs the hooks (console, `fetch`/`XMLHttpRequest`, user journey, `ErrorHandler`);\n * otherwise it loads and installs nothing. `<lt-bug-report>` renders the button and opens the dialog for {@link open}\n * requests.\n */\n@Service()\nexport class LtBugReportService {\n /** Resolved options. */\n readonly options = inject(LT_BUG_OPTIONS);\n\n private readonly document = inject(DOCUMENT);\n private readonly injector = inject(Injector);\n private readonly i18n = inject(LtI18nService);\n private readonly i18nOptions = inject(LT_I18N_OPTIONS);\n private readonly toast = inject(LtToastService);\n private readonly screenshotLoader = inject(LT_BUG_SCREENSHOT_LOADER);\n\n /**\n * Whether the reporter runs: `provideLtBug()` is present, the code runs in the browser and the runtime decision says\n * on (`enabled`, else app env not `production`, else dev mode only). Decided once at startup.\n */\n readonly active: boolean =\n inject(LT_BUG_INPUT_OPTIONS) !== null &&\n isPlatformBrowser(inject(PLATFORM_ID)) &&\n isLtBugActive(this.options, inject(LT_RUNTIME_CONFIG, { optional: true })?.appEnv, inject(LT_BUG_DEV_MODE));\n\n /** The dialog is open (or about to open). */\n readonly isOpen = signal(false);\n /** A report is being sent. */\n readonly isSubmitting = signal(false);\n /** Message of the last failed submission (shown in the dialog). */\n readonly error = signal<string | null>(null);\n /** The last captured error (pre-fills the form). */\n readonly lastError = signal<LtBugErrorInfo | null>(null);\n /** Screenshot taken before the dialog opened (data URL). */\n readonly screenshot = signal<string | null>(null);\n /** A screenshot is being taken. */\n readonly capturingScreenshot = signal(false);\n /** Whether `modern-screenshot` could be loaded (`null` until the first attempt). */\n readonly screenshotAvailable = signal<boolean | null>(null);\n /** An {@link open} request waits for `<lt-bug-report>` (read and reset by the component). */\n readonly openRequested = signal(false);\n\n private engine: LtBugCaptureEngine | null = null;\n private engineLoad: Promise<LtBugCaptureEngine | null> = Promise.resolve(null);\n private pendingErrors: { error: unknown; source?: string }[] = [];\n private started = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.stop());\n }\n\n /** Whether the capture hooks are installed. */\n get running(): boolean {\n return this.engine !== null;\n }\n\n /**\n * Load the capture engine and install the hooks for the enabled features (idempotent; does nothing while not\n * {@link active}). Errors reported before the engine is ready are handed over once it is.\n */\n start(): void {\n const view = this.document.defaultView;\n if (!this.active || this.started || !view) {\n return;\n }\n this.started = true;\n const router = this.injector.get(ROUTES, null) ? this.injector.get(Router, null) : null;\n const errorHandler = this.injector.get(ErrorHandler, null);\n this.engineLoad = import('./capture-engine').then(\n ({ startLtBugCapture }) => {\n if (!this.started) {\n return null;\n }\n this.engine = startLtBugCapture({ baseUri: this.document.baseURI, errorHandler, onError: (info) => this.onCapturedError(info), options: this.options, router, view });\n for (const { error, source } of this.pendingErrors.splice(0)) {\n this.engine.reportError(error, source);\n }\n return this.engine;\n },\n (error: unknown) => {\n console.warn('[@lenne.tech/ng-base/bug] Could not load the capture engine', error);\n return null;\n },\n );\n }\n\n /** Resolves once {@link start} has installed the hooks (`false` when inactive or the engine failed to load). */\n async whenReady(): Promise<boolean> {\n return (await this.engineLoad) !== null;\n }\n\n /** Remove every capture hook and restore the patched globals. */\n stop(): void {\n this.engine?.stop();\n this.engine = null;\n this.engineLoad = Promise.resolve(null);\n this.pendingErrors = [];\n this.started = false;\n }\n\n /**\n * Ask `<lt-bug-report>` to take a screenshot and open the dialog (also when the floating button is hidden with\n * `autoShow: false`); `error` pre-fills the form. Ignored while the reporter is not active.\n */\n open(error?: LtBugErrorInfo): void {\n if (!this.active) {\n return;\n }\n if (error) {\n this.lastError.set(error);\n }\n this.error.set(null);\n this.openRequested.set(true);\n }\n\n /** Report an error by hand (e.g. from a `catch` block): it becomes {@link lastError} and may auto-open the dialog. */\n reportError(error: unknown, source?: string): void {\n if (!this.active || !this.started) {\n return;\n }\n if (this.engine) {\n this.engine.reportError(error, source);\n } else {\n this.pendingErrors.push({ error, source });\n }\n }\n\n /** Record a custom user journey event (no-op while the journey is off). */\n recordInteraction(type: LtUserInteractionType, target: string, metadata?: LtUserInteractionMetadata): void {\n this.engine?.record(type, target, metadata);\n }\n\n /** The captured console entries (newest `maxConsoleLogs`). */\n getConsoleLogs(): LtConsoleLogEntry[] {\n return this.engine?.consoleLogs() ?? [];\n }\n\n /** The captured network requests (newest `maxNetworkRequests`). */\n getNetworkRequests(): LtNetworkRequestEntry[] {\n return this.engine?.networkRequests() ?? [];\n }\n\n /** The captured user journey (newest `userJourney.maxEvents`). */\n getUserJourney(): LtUserInteractionEvent[] {\n return this.engine?.userJourney() ?? [];\n }\n\n /** Browser details of the current page (`null` while inactive or outside the browser). */\n getBrowserInfo(): LtBrowserInfo | null {\n return this.engine?.browserInfo() ?? null;\n }\n\n /**\n * Take a viewport screenshot into {@link screenshot} (without the reporter's UI; network capture paused meanwhile).\n * Resolves `null` when screenshots are disabled, `modern-screenshot` is missing or the capture failed.\n */\n async captureScreenshot(): Promise<string | null> {\n const view = this.document.defaultView;\n if (!this.active || !this.options.enableScreenshot || !view) {\n return null;\n }\n this.capturingScreenshot.set(true);\n this.engine?.setNetworkPaused(true);\n try {\n const library = await this.screenshotLoader();\n this.screenshotAvailable.set(!!library);\n const dataUrl = library ? await captureLtBugScreenshot(library, view, this.options.theme) : null;\n this.screenshot.set(dataUrl);\n return dataUrl;\n } catch (error) {\n console.warn('[@lenne.tech/ng-base/bug] Screenshot capture failed', error);\n this.screenshot.set(null);\n return null;\n } finally {\n this.capturingScreenshot.set(false);\n this.engine?.setNetworkPaused(false);\n }\n }\n\n /** Assemble the payload from the form, the attachments and the collected data the user kept switched on. */\n async buildReport(form: LtBugReportFormValue, attachments: readonly LtBugAttachment[], includes: LtBugReportIncludes): Promise<LtBugReportData> {\n const engine = await this.engineLoad;\n if (engine) {\n return engine.buildReport(form, attachments, includes);\n }\n const { buildLtBugReport } = await import('./report');\n return buildLtBugReport(form, attachments, includes, {});\n }\n\n /**\n * POST the report to the endpoint. Shows a success or error toast; on failure sets {@link error} and rejects with a\n * {@link LtBugSubmitError} carrying the translated message.\n */\n async submit(report: LtBugReportData): Promise<LtBugReportResponse> {\n this.isSubmitting.set(true);\n this.error.set(null);\n try {\n // The texts of toasts and errors live in the lazy part (also when an app submits without the dialog).\n await loadLtBugMessages(this.i18n, this.i18nOptions.messages);\n const view = this.document.defaultView;\n if (!view?.fetch) {\n throw new LtBugSubmitError(this.i18n.t('lt.bug.errorSubmit'), 0);\n }\n let response: Response;\n try {\n response = await view.fetch(this.options.endpoint, {\n body: JSON.stringify(report),\n credentials: 'same-origin',\n headers: { accept: 'application/json', 'content-type': 'application/json' },\n method: 'POST',\n });\n } catch {\n throw new LtBugSubmitError(this.i18n.t('lt.bug.errorSubmit'), 0);\n }\n let body: LtBugReportResponse | null = null;\n try {\n body = (await response.json()) as LtBugReportResponse;\n } catch {\n body = null;\n }\n if (!response.ok || !body?.success) {\n throw new LtBugSubmitError(this.messageForStatus(response.status), response.status);\n }\n this.toast.show({\n color: 'success',\n description: body.identifier ? this.i18n.t('lt.bug.successDescription', { identifier: body.identifier }) : undefined,\n duration: 5000,\n title: this.i18n.t('lt.bug.successTitle'),\n });\n return body;\n } catch (error) {\n const failure = error instanceof LtBugSubmitError ? error : new LtBugSubmitError(this.i18n.t('lt.bug.errorSubmit'), 0);\n this.error.set(failure.message);\n this.toast.show({ color: 'error', description: failure.message, duration: 7000, title: this.i18n.t('lt.bug.errorTitle') });\n throw failure;\n } finally {\n this.isSubmitting.set(false);\n }\n }\n\n /** Forget screenshot, pre-fill error and submission error (after a sent report). */\n reset(): void {\n this.screenshot.set(null);\n this.lastError.set(null);\n this.error.set(null);\n }\n\n private onCapturedError(info: LtBugErrorInfo): void {\n // Errors may arrive while Angular renders a template: update the state outside of it.\n queueMicrotask(() => {\n this.lastError.set(info);\n if (this.options.autoOpenOnError && !this.isOpen()) {\n this.open(info);\n }\n });\n }\n\n private messageForStatus(status: number): string {\n switch (status) {\n case 400:\n return this.i18n.t('lt.bug.errorInvalid');\n case 404:\n return this.i18n.t('lt.bug.errorUnavailable');\n case 413:\n return this.i18n.t('lt.bug.errorTooLarge');\n case 429:\n return this.i18n.t('lt.bug.errorRateLimited');\n default:\n return this.i18n.t('lt.bug.errorSubmit');\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"lenne.tech-ng-base-bug-bug-report-service-D6slR3GD.mjs","names":["LT_BUG_INPUT_OPTIONS"],"sources":["../../../projects/ng-base/bug/src/lib/bug-options.ts","../../../projects/ng-base/bug/src/lib/i18n/load.ts","../../../projects/ng-base/bug/src/lib/screenshot.ts","../../../projects/ng-base/bug/src/lib/bug-report-service.ts"],"sourcesContent":["import { inject, InjectionToken } from '@angular/core';\nimport { LT_RUNTIME_CONFIG, mergeLtFeatureOptions } from '@lenne.tech/ng-base';\nimport { LT_BUG_INPUT_OPTIONS, type LtBugOptions, type LtResolvedBugOptions } from '@lenne.tech/ng-base/bug/provide';\n\n/** The runtime decision lives in `@lenne.tech/ng-base/bug/provide` (light entry for `app.config.ts` and the shell). */\nexport { isLtBugActive, LT_BUG_ACTIVE, LT_BUG_DEV_MODE, LT_BUG_INPUT_OPTIONS } from '@lenne.tech/ng-base/bug/provide';\n\n/** Default endpoint, the same as `@lenne.tech/bug.lt` (outside `/api`, so an API proxy does not swallow it). */\nexport const LT_BUG_DEFAULT_ENDPOINT = '/_bug-lt/report';\n\n/** Defaults of {@link LtBugOptions} (the module defaults of `@lenne.tech/bug.lt` 1.6.9, except the button color). */\nexport const LT_BUG_DEFAULTS: LtResolvedBugOptions = {\n autoOpenOnError: false,\n autoShow: true,\n // bug.lt: #ef4444; white text on it has 3.8:1 contrast (WCAG AA needs 4.5:1), red-600 has 4.8:1.\n buttonColor: '#dc2626',\n enableBrowserInfo: true,\n enableConsoleLogs: true,\n enableErrorBoundary: true,\n enableNetworkRequests: true,\n enableScreenshot: true,\n enableUserJourney: true,\n endpoint: LT_BUG_DEFAULT_ENDPOINT,\n maxConsoleLogs: 50,\n maxNetworkRequests: 50,\n position: 'bottom-right',\n theme: 'auto',\n userJourney: {\n captureClicks: true,\n captureErrors: true,\n captureFormInteractions: true,\n captureHover: false,\n captureInputChanges: false,\n captureInputValues: false,\n captureKeyboard: true,\n captureModalEvents: true,\n captureNavigation: true,\n captureScroll: false,\n enabled: true,\n maxEvents: 50,\n throttleRate: 100,\n },\n};\n\n/** Resolved options: defaults ← `provideLtBug(options)` ← runtime `lt.bug` (`LT_RUNTIME_CONFIG`). */\nexport const LT_BUG_OPTIONS = new InjectionToken<LtResolvedBugOptions>('LT_BUG_OPTIONS', {\n factory: () => resolveLtBugOptions(inject(LT_BUG_INPUT_OPTIONS) ?? {}, inject(LT_RUNTIME_CONFIG, { optional: true })?.lt?.['bug']),\n});\n\n/** Merge options onto the defaults; `userJourney` is merged per key, `undefined` never overrides, sizes are clamped. */\nexport function resolveLtBugOptions(...overrides: (LtBugOptions | Record<string, unknown> | null | undefined)[]): LtResolvedBugOptions {\n const merged = mergeLtFeatureOptions<LtResolvedBugOptions>(LT_BUG_DEFAULTS, ...overrides);\n return {\n ...merged,\n endpoint: typeof merged.endpoint === 'string' && merged.endpoint.startsWith('/') ? merged.endpoint : LT_BUG_DEFAULT_ENDPOINT,\n maxConsoleLogs: clampSize(merged.maxConsoleLogs, LT_BUG_DEFAULTS.maxConsoleLogs),\n maxNetworkRequests: clampSize(merged.maxNetworkRequests, LT_BUG_DEFAULTS.maxNetworkRequests),\n userJourney: {\n ...merged.userJourney,\n maxEvents: clampSize(merged.userJourney.maxEvents, LT_BUG_DEFAULTS.userJourney.maxEvents),\n throttleRate: Math.max(0, Number(merged.userJourney.throttleRate) || 0),\n },\n };\n}\n\n/** Ring buffer sizes are whole numbers between 1 and 1000. */\nfunction clampSize(value: unknown, fallback: number): number {\n const number = Math.floor(Number(value));\n return Number.isFinite(number) && number > 0 ? Math.min(number, 1000) : fallback;\n}\n","import type { LtI18nMessages, LtI18nService } from '@lenne.tech/ng-base';\n\n/**\n * The only texts needed before the dialog chunk is loaded: the floating button's label and its busy text. Kept equal to\n * `de.json` / `en.json` (checked by `i18n.spec.ts`).\n */\nexport const LT_BUG_EAGER_MESSAGES: Readonly<Record<'de' | 'en', LtI18nMessages>> = {\n de: { lt: { bug: { button: 'Fehler melden', capturing: 'Screenshot wird erstellt …' } } },\n en: { lt: { bug: { button: 'Report a bug', capturing: 'Taking screenshot …' } } },\n};\n\nconst loaded = new WeakSet<LtI18nService>();\nlet messagesModule: Promise<typeof import('./messages')> | null = null;\n\n/** Register the button texts (synchronously; texts the app configured keep priority). */\nexport function registerLtBugEagerMessages(i18n: LtI18nService, appMessages: Record<string, LtI18nMessages> = {}): void {\n for (const [locale, messages] of Object.entries(LT_BUG_EAGER_MESSAGES)) {\n const app = appMessages[locale];\n i18n.registerMessages(locale, app ? withAppTexts(messages, app) : messages);\n }\n}\n\n/** Load (lazy chunk) and register every `lt.bug.*` text once per `LtI18nService` instance. */\nexport async function loadLtBugMessages(i18n: LtI18nService, appMessages: Record<string, LtI18nMessages> = {}): Promise<void> {\n if (loaded.has(i18n)) {\n return;\n }\n messagesModule ??= import('./messages');\n try {\n (await messagesModule).registerLtBugMessages(i18n, appMessages);\n loaded.add(i18n);\n } catch {\n // Chunk failed to load: keep the keys, retry on the next call.\n messagesModule = null;\n }\n}\n\nfunction withAppTexts(base: LtI18nMessages, app: LtI18nMessages): LtI18nMessages {\n const result: LtI18nMessages = { ...base };\n for (const [key, value] of Object.entries(app)) {\n const current = result[key];\n if (current === undefined) {\n continue;\n }\n result[key] = typeof value === 'object' && typeof current === 'object' ? withAppTexts(current, value) : value;\n }\n return result;\n}\n","import { InjectionToken } from '@angular/core';\n\nimport type { LtBugTheme } from './bug-types';\nimport { LT_BUG_UI_ATTRIBUTE } from './constants';\n\n/** The part of `modern-screenshot` the reporter uses (structural, so the peer stays optional). */\nexport interface LtScreenshotLibrary {\n domToPng(node: Node, options?: Record<string, unknown>): Promise<string>;\n}\n\nlet library: Promise<LtScreenshotLibrary | null> | null = null;\n\n/** Load the optional peer `modern-screenshot` once; resolves `null` when it is not installed. */\nexport function loadLtScreenshotLibrary(): Promise<LtScreenshotLibrary | null> {\n library ??= import('modern-screenshot').then(\n (module) => {\n const candidate = module as unknown as Partial<LtScreenshotLibrary> & { default?: Partial<LtScreenshotLibrary> };\n const resolved = typeof candidate.domToPng === 'function' ? candidate : candidate.default;\n return typeof resolved?.domToPng === 'function' ? (resolved as LtScreenshotLibrary) : null;\n },\n () => null,\n );\n return library;\n}\n\n/**\n * Loader of the screenshot library (default: lazy `import('modern-screenshot')`, `null` when the optional peer is\n * missing: the screenshot feature is then hidden). Replace it in tests.\n */\nexport const LT_BUG_SCREENSHOT_LOADER = new InjectionToken<() => Promise<LtScreenshotLibrary | null>>('LT_BUG_SCREENSHOT_LOADER', {\n factory: () => loadLtScreenshotLibrary,\n});\n\n/**\n * PNG data URL of the visible viewport (current scroll position, device pixel ratio up to 2), without the reporter's\n * own UI. The background follows `theme` (`auto`: `html.dark` / `html.light`, then `color-scheme`, then the system).\n */\nexport function captureLtBugScreenshot(lib: LtScreenshotLibrary, view: Window, theme: LtBugTheme): Promise<string> {\n const doc = view.document;\n const dark = theme === 'dark' || (theme === 'auto' && isLtDarkColorMode(view));\n return lib.domToPng(doc.documentElement, {\n backgroundColor: dark ? '#0a0a0a' : '#ffffff',\n features: { restoreScrollPosition: true },\n fetch: { bypassingCache: true, requestInit: { mode: 'cors' } },\n filter: (node: Node) => !(node.nodeType === 1 && (node as Element).hasAttribute?.(LT_BUG_UI_ATTRIBUTE)),\n height: view.innerHeight,\n scale: Math.min(view.devicePixelRatio || 1, 2),\n style: { transform: 'none', transformOrigin: 'top left' },\n width: view.innerWidth,\n });\n}\n\n/** Whether the page currently renders dark (`html.dark`, `html.light`, computed `color-scheme`, system preference). */\nexport function isLtDarkColorMode(view: Window): boolean {\n const root = view.document?.documentElement;\n if (root?.classList.contains('dark')) {\n return true;\n }\n if (root?.classList.contains('light')) {\n return false;\n }\n const scheme = root && typeof view.getComputedStyle === 'function' ? view.getComputedStyle(root).colorScheme : '';\n if (scheme === 'dark' || scheme === 'light') {\n return scheme === 'dark';\n }\n return !!view.matchMedia?.('(prefers-color-scheme: dark)').matches;\n}\n","import { DOCUMENT, isPlatformBrowser } from '@angular/common';\nimport { DestroyRef, ErrorHandler, inject, Injector, PLATFORM_ID, Service, signal } from '@angular/core';\nimport { Router, ROUTES } from '@angular/router';\nimport { LT_I18N_OPTIONS, LT_RUNTIME_CONFIG, LtI18nService, LtToastService } from '@lenne.tech/ng-base';\n\nimport { isLtBugActive, LT_BUG_DEV_MODE, LT_BUG_INPUT_OPTIONS, LT_BUG_OPTIONS } from './bug-options';\nimport type {\n LtBrowserInfo,\n LtBugAttachment,\n LtBugErrorInfo,\n LtBugReportData,\n LtBugReportResponse,\n LtConsoleLogEntry,\n LtNetworkRequestEntry,\n LtUserInteractionEvent,\n LtUserInteractionMetadata,\n LtUserInteractionType,\n} from './bug-types';\nimport type { LtBugCaptureEngine } from './capture-engine';\nimport { loadLtBugMessages } from './i18n/load';\nimport type { LtBugReportFormValue, LtBugReportIncludes } from './report';\nimport { captureLtBugScreenshot, LT_BUG_SCREENSHOT_LOADER } from './screenshot';\n\n/** Error of {@link LtBugReportService.submit}; `message` is the translated text shown to the user. */\nexport class LtBugSubmitError extends Error {\n constructor(\n message: string,\n readonly status: number,\n ) {\n super(message);\n this.name = 'LtBugSubmitError';\n }\n}\n\n/**\n * State and actions of the bug reporter, the counterpart of `useBugReport()` of `@lenne.tech/bug.lt`.\n *\n * `<lt-bug-report>` calls {@link start} when it is created: when the reporter is {@link active} it loads the capture engine\n * (a chunk of its own) and installs the hooks (console, `fetch`/`XMLHttpRequest`, user journey, `ErrorHandler`);\n * otherwise it loads and installs nothing. `<lt-bug-report>` renders the button and opens the dialog for {@link open}\n * requests.\n */\n@Service()\nexport class LtBugReportService {\n /** Resolved options. */\n readonly options = inject(LT_BUG_OPTIONS);\n\n private readonly document = inject(DOCUMENT);\n private readonly injector = inject(Injector);\n private readonly i18n = inject(LtI18nService);\n private readonly i18nOptions = inject(LT_I18N_OPTIONS);\n private readonly toast = inject(LtToastService);\n private readonly screenshotLoader = inject(LT_BUG_SCREENSHOT_LOADER);\n\n /**\n * Whether the reporter runs: `provideLtBug()` is present, the code runs in the browser and the runtime decision says\n * on (`enabled`, else app env not `production`, else dev mode only). Decided once at startup.\n */\n readonly active: boolean =\n inject(LT_BUG_INPUT_OPTIONS) !== null &&\n isPlatformBrowser(inject(PLATFORM_ID)) &&\n isLtBugActive(this.options, inject(LT_RUNTIME_CONFIG, { optional: true })?.appEnv, inject(LT_BUG_DEV_MODE));\n\n /** The dialog is open (or about to open). */\n readonly isOpen = signal(false);\n /** A report is being sent. */\n readonly isSubmitting = signal(false);\n /** Message of the last failed submission (shown in the dialog). */\n readonly error = signal<string | null>(null);\n /** The last captured error (pre-fills the form). */\n readonly lastError = signal<LtBugErrorInfo | null>(null);\n /** Screenshot taken before the dialog opened (data URL). */\n readonly screenshot = signal<string | null>(null);\n /** A screenshot is being taken. */\n readonly capturingScreenshot = signal(false);\n /** Whether `modern-screenshot` could be loaded (`null` until the first attempt). */\n readonly screenshotAvailable = signal<boolean | null>(null);\n /** An {@link open} request waits for `<lt-bug-report>` (read and reset by the component). */\n readonly openRequested = signal(false);\n\n private engine: LtBugCaptureEngine | null = null;\n private engineLoad: Promise<LtBugCaptureEngine | null> = Promise.resolve(null);\n private pendingErrors: { error: unknown; source?: string }[] = [];\n private started = false;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.stop());\n }\n\n /** Whether the capture hooks are installed. */\n get running(): boolean {\n return this.engine !== null;\n }\n\n /**\n * Load the capture engine and install the hooks for the enabled features (idempotent; does nothing while not\n * {@link active}). Errors reported before the engine is ready are handed over once it is.\n */\n start(): void {\n const view = this.document.defaultView;\n if (!this.active || this.started || !view) {\n return;\n }\n this.started = true;\n const router = this.injector.get(ROUTES, null) ? this.injector.get(Router, null) : null;\n const errorHandler = this.injector.get(ErrorHandler, null);\n this.engineLoad = import('./capture-engine').then(\n ({ startLtBugCapture }) => {\n if (!this.started) {\n return null;\n }\n this.engine = startLtBugCapture({ baseUri: this.document.baseURI, errorHandler, onError: (info) => this.onCapturedError(info), options: this.options, router, view });\n for (const { error, source } of this.pendingErrors.splice(0)) {\n this.engine.reportError(error, source);\n }\n return this.engine;\n },\n (error: unknown) => {\n console.warn('[@lenne.tech/ng-base/bug] Could not load the capture engine', error);\n return null;\n },\n );\n }\n\n /** Resolves once {@link start} has installed the hooks (`false` when inactive or the engine failed to load). */\n async whenReady(): Promise<boolean> {\n return (await this.engineLoad) !== null;\n }\n\n /** Remove every capture hook and restore the patched globals. */\n stop(): void {\n this.engine?.stop();\n this.engine = null;\n this.engineLoad = Promise.resolve(null);\n this.pendingErrors = [];\n this.started = false;\n }\n\n /**\n * Ask `<lt-bug-report>` to take a screenshot and open the dialog (also when the floating button is hidden with\n * `autoShow: false`); `error` pre-fills the form. Ignored while the reporter is not active.\n */\n open(error?: LtBugErrorInfo): void {\n if (!this.active) {\n return;\n }\n if (error) {\n this.lastError.set(error);\n }\n this.error.set(null);\n this.openRequested.set(true);\n }\n\n /** Report an error by hand (e.g. from a `catch` block): it becomes {@link lastError} and may auto-open the dialog. */\n reportError(error: unknown, source?: string): void {\n if (!this.active || !this.started) {\n return;\n }\n if (this.engine) {\n this.engine.reportError(error, source);\n } else {\n this.pendingErrors.push({ error, source });\n }\n }\n\n /** Record a custom user journey event (no-op while the journey is off). */\n recordInteraction(type: LtUserInteractionType, target: string, metadata?: LtUserInteractionMetadata): void {\n this.engine?.record(type, target, metadata);\n }\n\n /** The captured console entries (newest `maxConsoleLogs`). */\n getConsoleLogs(): LtConsoleLogEntry[] {\n return this.engine?.consoleLogs() ?? [];\n }\n\n /** The captured network requests (newest `maxNetworkRequests`). */\n getNetworkRequests(): LtNetworkRequestEntry[] {\n return this.engine?.networkRequests() ?? [];\n }\n\n /** The captured user journey (newest `userJourney.maxEvents`). */\n getUserJourney(): LtUserInteractionEvent[] {\n return this.engine?.userJourney() ?? [];\n }\n\n /** Browser details of the current page (`null` while inactive or outside the browser). */\n getBrowserInfo(): LtBrowserInfo | null {\n return this.engine?.browserInfo() ?? null;\n }\n\n /**\n * Take a viewport screenshot into {@link screenshot} (without the reporter's UI; network capture paused meanwhile).\n * Resolves `null` when screenshots are disabled, `modern-screenshot` is missing or the capture failed.\n */\n async captureScreenshot(): Promise<string | null> {\n const view = this.document.defaultView;\n if (!this.active || !this.options.enableScreenshot || !view) {\n return null;\n }\n this.capturingScreenshot.set(true);\n this.engine?.setNetworkPaused(true);\n try {\n const library = await this.screenshotLoader();\n this.screenshotAvailable.set(!!library);\n const dataUrl = library ? await captureLtBugScreenshot(library, view, this.options.theme) : null;\n this.screenshot.set(dataUrl);\n return dataUrl;\n } catch (error) {\n console.warn('[@lenne.tech/ng-base/bug] Screenshot capture failed', error);\n this.screenshot.set(null);\n return null;\n } finally {\n this.capturingScreenshot.set(false);\n this.engine?.setNetworkPaused(false);\n }\n }\n\n /** Assemble the payload from the form, the attachments and the collected data the user kept switched on. */\n async buildReport(form: LtBugReportFormValue, attachments: readonly LtBugAttachment[], includes: LtBugReportIncludes): Promise<LtBugReportData> {\n const engine = await this.engineLoad;\n if (engine) {\n return engine.buildReport(form, attachments, includes);\n }\n const { buildLtBugReport } = await import('./report');\n return buildLtBugReport(form, attachments, includes, {});\n }\n\n /**\n * POST the report to the endpoint. Shows a success or error toast; on failure sets {@link error} and rejects with a\n * {@link LtBugSubmitError} carrying the translated message.\n */\n async submit(report: LtBugReportData): Promise<LtBugReportResponse> {\n this.isSubmitting.set(true);\n this.error.set(null);\n try {\n // The texts of toasts and errors live in the lazy part (also when an app submits without the dialog).\n await loadLtBugMessages(this.i18n, this.i18nOptions.messages);\n const view = this.document.defaultView;\n if (!view?.fetch) {\n throw new LtBugSubmitError(this.i18n.t('lt.bug.errorSubmit'), 0);\n }\n let response: Response;\n try {\n response = await view.fetch(this.options.endpoint, {\n body: JSON.stringify(report),\n credentials: 'same-origin',\n headers: { accept: 'application/json', 'content-type': 'application/json' },\n method: 'POST',\n });\n } catch {\n throw new LtBugSubmitError(this.i18n.t('lt.bug.errorSubmit'), 0);\n }\n let body: LtBugReportResponse | null = null;\n try {\n body = (await response.json()) as LtBugReportResponse;\n } catch {\n body = null;\n }\n if (!response.ok || !body?.success) {\n throw new LtBugSubmitError(this.messageForStatus(response.status), response.status);\n }\n this.toast.show({\n color: 'success',\n description: body.identifier ? this.i18n.t('lt.bug.successDescription', { identifier: body.identifier }) : undefined,\n duration: 5000,\n title: this.i18n.t('lt.bug.successTitle'),\n });\n return body;\n } catch (error) {\n const failure = error instanceof LtBugSubmitError ? error : new LtBugSubmitError(this.i18n.t('lt.bug.errorSubmit'), 0);\n this.error.set(failure.message);\n this.toast.show({ color: 'error', description: failure.message, duration: 7000, title: this.i18n.t('lt.bug.errorTitle') });\n throw failure;\n } finally {\n this.isSubmitting.set(false);\n }\n }\n\n /** Forget screenshot, pre-fill error and submission error (after a sent report). */\n reset(): void {\n this.screenshot.set(null);\n this.lastError.set(null);\n this.error.set(null);\n }\n\n private onCapturedError(info: LtBugErrorInfo): void {\n // Errors may arrive while Angular renders a template: update the state outside of it.\n queueMicrotask(() => {\n this.lastError.set(info);\n if (this.options.autoOpenOnError && !this.isOpen()) {\n this.open(info);\n }\n });\n }\n\n private messageForStatus(status: number): string {\n switch (status) {\n case 400:\n return this.i18n.t('lt.bug.errorInvalid');\n case 404:\n return this.i18n.t('lt.bug.errorUnavailable');\n case 413:\n return this.i18n.t('lt.bug.errorTooLarge');\n case 429:\n return this.i18n.t('lt.bug.errorRateLimited');\n default:\n return this.i18n.t('lt.bug.errorSubmit');\n }\n }\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { a as LT_BUG_DEFAULTS, c as resolveLtBugOptions, i as registerLtBugEagerMessages, n as LtBugSubmitError, o as LT_BUG_DEFAULT_ENDPOINT, r as LT_BUG_SCREENSHOT_LOADER, s as LT_BUG_OPTIONS, t as LtBugReportService } from "./lenne.tech-ng-base-bug-bug-report-service-DWoTb_iw.mjs";
1
+ import { a as LT_BUG_DEFAULTS, c as resolveLtBugOptions, i as registerLtBugEagerMessages, n as LtBugSubmitError, o as LT_BUG_DEFAULT_ENDPOINT, r as LT_BUG_SCREENSHOT_LOADER, s as LT_BUG_OPTIONS, t as LtBugReportService } from "./lenne.tech-ng-base-bug-bug-report-service-D6slR3GD.mjs";
2
2
  import { t as LT_BUG_UI_ATTRIBUTE } from "./lenne.tech-ng-base-bug-constants-Brm2KGHi.mjs";
3
3
  import * as i0 from "@angular/core";
4
4
  import { Component, Injector, booleanAttribute, computed, effect, inject, input, signal, untracked } from "@angular/core";
@@ -46,7 +46,7 @@ var LtBugReport = class LtBugReport {
46
46
  this.announcement.set("");
47
47
  try {
48
48
  await this.bug.captureScreenshot();
49
- const { openLtBugReportDialog } = await import("./lenne.tech-ng-base-bug-bug-report-dialog-BRzVmKJr.mjs");
49
+ const { openLtBugReportDialog } = await import("./lenne.tech-ng-base-bug-bug-report-dialog-f6VNOWnW.mjs");
50
50
  const sent = await openLtBugReportDialog(this.injector).closed === true;
51
51
  if (sent) this.announcement.set(this.i18n.t("lt.bug.successTitle"));
52
52
  return sent;
@@ -59,7 +59,7 @@ var LtBugReport = class LtBugReport {
59
59
  }
60
60
  static ɵfac = i0.ɵɵngDeclareFactory({
61
61
  minVersion: "12.0.0",
62
- version: "22.2.4",
62
+ version: "22.2.5",
63
63
  ngImport: i0,
64
64
  type: LtBugReport,
65
65
  deps: [],
@@ -67,7 +67,7 @@ var LtBugReport = class LtBugReport {
67
67
  });
68
68
  static ɵcmp = i0.ɵɵngDeclareComponent({
69
69
  minVersion: "17.0.0",
70
- version: "22.2.4",
70
+ version: "22.2.5",
71
71
  type: LtBugReport,
72
72
  isStandalone: true,
73
73
  selector: "lt-bug-report",
@@ -131,7 +131,7 @@ var LtBugReport = class LtBugReport {
131
131
  };
132
132
  i0.ɵɵngDeclareClassMetadata({
133
133
  minVersion: "12.0.0",
134
- version: "22.2.4",
134
+ version: "22.2.5",
135
135
  ngImport: i0,
136
136
  type: LtBugReport,
137
137
  decorators: [{
@@ -194,7 +194,7 @@ var LtTusUploadComponent = class LtTusUploadComponent {
194
194
  }
195
195
  static ɵfac = i0.ɵɵngDeclareFactory({
196
196
  minVersion: "12.0.0",
197
- version: "22.2.4",
197
+ version: "22.2.5",
198
198
  ngImport: i0,
199
199
  type: LtTusUploadComponent,
200
200
  deps: [],
@@ -202,7 +202,7 @@ var LtTusUploadComponent = class LtTusUploadComponent {
202
202
  });
203
203
  static ɵcmp = i0.ɵɵngDeclareComponent({
204
204
  minVersion: "17.0.0",
205
- version: "22.2.4",
205
+ version: "22.2.5",
206
206
  type: LtTusUploadComponent,
207
207
  isStandalone: true,
208
208
  selector: "lt-tus-upload",
@@ -321,7 +321,7 @@ var LtTusUploadComponent = class LtTusUploadComponent {
321
321
  };
322
322
  i0.ɵɵngDeclareClassMetadata({
323
323
  minVersion: "12.0.0",
324
- version: "22.2.4",
324
+ version: "22.2.5",
325
325
  ngImport: i0,
326
326
  type: LtTusUploadComponent,
327
327
  decorators: [{
@@ -67,7 +67,7 @@ var LtFileService = class LtFileService {
67
67
  }
68
68
  static ɵfac = i0.ɵɵngDeclareFactory({
69
69
  minVersion: "12.0.0",
70
- version: "22.2.4",
70
+ version: "22.2.5",
71
71
  ngImport: i0,
72
72
  type: LtFileService,
73
73
  deps: [],
@@ -75,14 +75,14 @@ var LtFileService = class LtFileService {
75
75
  });
76
76
  static ɵprov = i0.ɵɵngDeclareService({
77
77
  minVersion: "22.0.0",
78
- version: "22.2.4",
78
+ version: "22.2.5",
79
79
  ngImport: i0,
80
80
  type: LtFileService
81
81
  });
82
82
  };
83
83
  i0.ɵɵngDeclareClassMetadata({
84
84
  minVersion: "12.0.0",
85
- version: "22.2.4",
85
+ version: "22.2.5",
86
86
  ngImport: i0,
87
87
  type: LtFileService,
88
88
  decorators: [{ type: Service }]
@@ -51,7 +51,7 @@ var LtShareService = class LtShareService {
51
51
  }
52
52
  static ɵfac = i0.ɵɵngDeclareFactory({
53
53
  minVersion: "12.0.0",
54
- version: "22.2.4",
54
+ version: "22.2.5",
55
55
  ngImport: i0,
56
56
  type: LtShareService,
57
57
  deps: [],
@@ -59,14 +59,14 @@ var LtShareService = class LtShareService {
59
59
  });
60
60
  static ɵprov = i0.ɵɵngDeclareService({
61
61
  minVersion: "22.0.0",
62
- version: "22.2.4",
62
+ version: "22.2.5",
63
63
  ngImport: i0,
64
64
  type: LtShareService
65
65
  });
66
66
  };
67
67
  i0.ɵɵngDeclareClassMetadata({
68
68
  minVersion: "12.0.0",
69
- version: "22.2.4",
69
+ version: "22.2.5",
70
70
  ngImport: i0,
71
71
  type: LtShareService,
72
72
  decorators: [{ type: Service }]
@@ -59,7 +59,7 @@ var LtColorModeService = class LtColorModeService {
59
59
  }
60
60
  static ɵfac = i0.ɵɵngDeclareFactory({
61
61
  minVersion: "12.0.0",
62
- version: "22.2.4",
62
+ version: "22.2.5",
63
63
  ngImport: i0,
64
64
  type: LtColorModeService,
65
65
  deps: [],
@@ -67,14 +67,14 @@ var LtColorModeService = class LtColorModeService {
67
67
  });
68
68
  static ɵprov = i0.ɵɵngDeclareService({
69
69
  minVersion: "22.0.0",
70
- version: "22.2.4",
70
+ version: "22.2.5",
71
71
  ngImport: i0,
72
72
  type: LtColorModeService
73
73
  });
74
74
  };
75
75
  i0.ɵɵngDeclareClassMetadata({
76
76
  minVersion: "12.0.0",
77
- version: "22.2.4",
77
+ version: "22.2.5",
78
78
  ngImport: i0,
79
79
  type: LtColorModeService,
80
80
  decorators: [{ type: Service }],