@lifecorner/angular-ui-kit 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-accordion.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-alert.mjs +16 -1
- package/fesm2022/lifecorner-angular-ui-kit-alert.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-bottom-nav.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs +4 -4
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-callout.mjs +16 -1
- package/fesm2022/lifecorner-angular-ui-kit-callout.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-chat.mjs +14 -1
- package/fesm2022/lifecorner-angular-ui-kit-chat.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-code-block.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-code-block.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-combobox.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-confirm-dialog.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-copy-field.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-date-range-picker.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-date-range-picker.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs +14 -1
- package/fesm2022/lifecorner-angular-ui-kit-document-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-drawer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-email-input.mjs +4 -0
- package/fesm2022/lifecorner-angular-ui-kit-email-input.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-file-upload.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-footer.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-footer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs +14 -1
- package/fesm2022/lifecorner-angular-ui-kit-gallery.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs +18 -1
- package/fesm2022/lifecorner-angular-ui-kit-header.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-icon.mjs +186 -275
- package/fesm2022/lifecorner-angular-ui-kit-icon.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-icons.mjs +803 -0
- package/fesm2022/lifecorner-angular-ui-kit-icons.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-icon-set.mjs +297 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-icon-set.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-navigation.mjs +38 -0
- package/fesm2022/lifecorner-angular-ui-kit-internal-navigation.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-kanban-board.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-log-viewer.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-modal.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-modal.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs +12 -1
- package/fesm2022/lifecorner-angular-ui-kit-next-step-card.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs +14 -1
- package/fesm2022/lifecorner-angular-ui-kit-notification-center.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-number-input.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-number-input.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-password-input.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-password-input.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs +12 -1
- package/fesm2022/lifecorner-angular-ui-kit-pipeline.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-rating.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-rating.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-search-input.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-search-input.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-sidenav-placeholder.mjs +262 -0
- package/fesm2022/lifecorner-angular-ui-kit-sidenav-placeholder.mjs.map +1 -0
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs +18 -40
- package/fesm2022/lifecorner-angular-ui-kit-sidenav.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +4 -1
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs +16 -1
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-tree-view.mjs +18 -1
- package/fesm2022/lifecorner-angular-ui-kit-tree-view.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit.mjs +2 -0
- package/package.json +17 -1
- package/types/lifecorner-angular-ui-kit-icon.d.ts +125 -5
- package/types/lifecorner-angular-ui-kit-icons.d.ts +140 -0
- package/types/lifecorner-angular-ui-kit-internal-icon-set.d.ts +31 -0
- package/types/lifecorner-angular-ui-kit-internal-navigation.d.ts +28 -0
- package/types/lifecorner-angular-ui-kit-sidenav-placeholder.d.ts +163 -0
- package/types/lifecorner-angular-ui-kit-sidenav.d.ts +4 -2
- package/types/lifecorner-angular-ui-kit.d.ts +2 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-combobox.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.ts","../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n afterRenderEffect,\n forwardRef,\n ElementRef,\n viewChild,\n HostListener,\n inject,\n untracked,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { Observable, Subject, catchError, debounce, defer, of, switchMap, timer } from 'rxjs';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\nimport { SpinnerComponent } from '@lifecorner/angular-ui-kit/spinner';\nimport { ChipComponent } from '@lifecorner/angular-ui-kit/chip';\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n description?: string;\n icon?: string;\n group?: string;\n disabled?: boolean;\n}\n\nexport type ComboboxValue = ComboboxOption | ComboboxOption[] | null;\n\nexport type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg';\n\n/**\n * Combobox / async autocomplete component.\n *\n * Supports free-text input with sync/async option suggestions,\n * single/multiple selection, create new entries, and keyboard navigation.\n * The suggestion list is rendered in a CDK overlay so it is never clipped\n * by `overflow: hidden` ancestors (cards, modals, table cells).\n *\n * @example\n * ```html\n * <lc-combobox\n * label=\"Assign to user\"\n * [loadOptions]=\"searchUsers\"\n * [(value)]=\"assignee\"\n * allowCreate\n * />\n * ```\n */\n@Component({\n selector: 'lc-combobox',\n standalone: true,\n imports: [OverlayModule, IconComponent, SpinnerComponent, ChipComponent],\n templateUrl: './combobox.component.html',\n styleUrls: ['./combobox.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => ComboboxComponent),\n multi: true,\n },\n ],\n})\nexport class ComboboxComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance ids so label/listbox/options can be linked via ARIA */\n readonly inputId = `lc-combobox-${++ComboboxComponent.nextId}`;\n readonly listboxId = `${this.inputId}-listbox`;\n protected readonly createOptionId = `${this.listboxId}-create`;\n\n private readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('inputEl');\n private readonly dropdownEl = viewChild<ElementRef<HTMLElement>>('dropdownEl');\n\n private readonly elRef = inject(ElementRef);\n private readonly querySubject = new Subject<string>();\n\n /** Sync options */\n readonly options = input<ComboboxOption[]>([]);\n\n /** Async option loader */\n readonly loadOptions = input<((query: string) => Observable<ComboboxOption[]>)>();\n\n /** Debounce for async queries */\n readonly debounceMs = input<number>(250);\n\n /** Minimum characters before triggering search */\n readonly minChars = input<number>(1);\n\n /** Placeholder text */\n readonly placeholder = input<string>('Search…');\n\n /** Label */\n readonly label = input<string>();\n\n /** Helper text */\n readonly helperText = input<string>();\n\n /** Error message */\n readonly error = input<string>();\n\n /** Disabled state */\n readonly disabled = input<boolean>(false);\n\n /** Allow multiple selections */\n readonly multiple = input<boolean>(false);\n\n /** Allow creating new entries */\n readonly allowCreate = input<boolean>(false);\n\n /** Show loading spinner (controlled) */\n readonly loading = input<boolean>(false);\n\n /** Empty state message */\n readonly emptyMessage = input<string>('No results');\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear');\n\n /** Label before the query in the \"create\" option (`allowCreate`): `Create \"query\"`. */\n readonly createOptionLabel = input('Create');\n\n /** Size */\n readonly size = input<ComboboxSize>('md');\n\n /** Value change event */\n readonly valueChange = output<ComboboxValue>();\n\n /** Query change event */\n readonly queryChange = output<string>();\n\n /** Option selected event */\n readonly optionSelected = output<ComboboxOption>();\n\n /** Created event (allowCreate) */\n readonly created = output<string>();\n\n /** Internal state */\n protected query = signal('');\n protected isOpen = signal(false);\n protected highlightedIndex = signal(-1);\n protected asyncOptions = signal<ComboboxOption[]>([]);\n protected isLoading = signal(false);\n\n /** Disabled via `setDisabledState` (reactive forms) */\n private readonly formDisabled = signal(false);\n\n /** Effective disabled state: `disabled` input OR form control disabled */\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n /** Selected values */\n protected selectedSingle = signal<ComboboxOption | null>(null);\n protected selectedMultiple = signal<ComboboxOption[]>([]);\n\n /** Resolved visible options */\n protected visibleOptions = computed(() => {\n const q = this.query().toLowerCase();\n const loader = this.loadOptions();\n\n let opts: ComboboxOption[];\n if (loader) {\n opts = this.asyncOptions();\n } else {\n opts = this.options();\n if (q.length >= this.minChars()) {\n opts = opts.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.value.toLowerCase().includes(q) ||\n (o.description && o.description.toLowerCase().includes(q))\n );\n }\n }\n\n // Remove already selected in multiple mode\n if (this.multiple()) {\n const selected = new Set(this.selectedMultiple().map((s) => s.value));\n opts = opts.filter((o) => !selected.has(o.value));\n }\n\n return opts;\n });\n\n /** Grouped options */\n protected groupedOptions = computed(() => {\n const opts = this.visibleOptions();\n const groups = new Map<string, ComboboxOption[]>();\n\n for (const opt of opts) {\n const group = opt.group || '';\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group)!.push(opt);\n }\n\n return Array.from(groups.entries()).map(([label, items]) => ({\n label,\n items,\n }));\n });\n\n /** Flat list for keyboard nav */\n protected flatOptions = computed(() => {\n return this.groupedOptions().flatMap((g) => g.items);\n });\n\n /** Whether to show \"Create\" option */\n protected showCreateOption = computed(() => {\n if (!this.allowCreate()) return false;\n const q = this.query().trim();\n if (!q) return false;\n const exact = this.visibleOptions().some(\n (o) => o.label.toLowerCase() === q.toLowerCase()\n );\n return !exact;\n });\n\n /** id of the highlighted option — announced via aria-activedescendant */\n protected readonly activeDescendantId = computed(() => {\n if (!this.isOpen()) return null;\n const i = this.highlightedIndex();\n if (i < 0) return null;\n if (i === this.flatOptions().length) {\n return this.showCreateOption() ? this.createOptionId : null;\n }\n return i < this.flatOptions().length ? this.optionId(i) : null;\n });\n\n /** ids referenced by aria-describedby (helper / error) */\n protected readonly describedBy = computed(() => {\n if (this.error()) return `${this.inputId}-error`;\n if (this.helperText()) return `${this.inputId}-helper`;\n return null;\n });\n\n /** Container classes */\n protected containerClasses = computed(() => {\n const classes = [`lc-combobox`, `lc-combobox--${this.size()}`];\n if (this.isDisabled()) classes.push('lc-combobox--disabled');\n if (this.error()) classes.push('lc-combobox--error');\n if (this.isOpen()) classes.push('lc-combobox--open');\n return classes.join(' ');\n });\n\n protected optionId(index: number): string {\n return `${this.listboxId}-opt-${index}`;\n }\n\n // ControlValueAccessor\n private onChange: (value: ComboboxValue) => void = () => { /* set by registerOnChange */ };\n private onTouched: () => void = () => { /* set by registerOnTouched */ };\n\n constructor() {\n // Async loading pipe. `debounce` (not `debounceTime`) reads the signal per\n // emission, so `debounceMs` is honoured after inputs are populated.\n this.querySubject\n .pipe(\n debounce(() => timer(this.debounceMs())),\n switchMap((q) => {\n const loader = this.loadOptions();\n if (!loader || q.length < this.minChars()) {\n return of([] as ComboboxOption[]);\n }\n this.isLoading.set(true);\n // `defer` turns a synchronously throwing loader into an error\n // notification; `catchError` keeps the pipe alive for the next query.\n return defer(() => loader(q)).pipe(catchError(() => of([] as ComboboxOption[])));\n }),\n takeUntilDestroyed()\n )\n .subscribe((results) => {\n this.asyncOptions.set(results);\n this.isLoading.set(false);\n });\n\n // Keep the highlighted option visible while navigating with the keyboard\n // (after render, so the option element exists in the overlay pane).\n afterRenderEffect(() => {\n const id = this.activeDescendantId();\n if (!id) return;\n untracked(() => {\n // ids are generated from a counter, so no CSS escaping is needed\n this.dropdownEl()\n ?.nativeElement.querySelector<HTMLElement>(`#${id}`)\n ?.scrollIntoView?.({ block: 'nearest' });\n });\n });\n }\n\n writeValue(value: ComboboxValue): void {\n if (this.multiple()) {\n this.selectedMultiple.set(Array.isArray(value) ? value : []);\n } else {\n const single = value && !Array.isArray(value) ? value : null;\n this.selectedSingle.set(single);\n this.query.set(single ? single.label : '');\n }\n }\n\n registerOnChange(fn: (value: ComboboxValue) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n if (isDisabled) this.isOpen.set(false);\n }\n\n /**\n * Clear the current selection and query. Emits `null` (single) or `[]`\n * (multiple) exactly once, like a user-initiated deselect.\n */\n clear(): void {\n this.query.set('');\n this.highlightedIndex.set(-1);\n this.isOpen.set(false);\n const value: ComboboxValue = this.multiple() ? [] : null;\n if (this.multiple()) {\n this.selectedMultiple.set([]);\n } else {\n this.selectedSingle.set(null);\n }\n this.onChange(value);\n this.valueChange.emit(value);\n }\n\n protected onClearClick(): void {\n if (this.isDisabled()) return;\n this.clear();\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onInputChange(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.query.set(value);\n this.queryChange.emit(value);\n this.highlightedIndex.set(-1);\n\n if (this.loadOptions()) {\n this.querySubject.next(value);\n }\n\n if (value.length >= this.minChars()) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputFocus(): void {\n if (this.query().length >= this.minChars() || this.options().length > 0) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputBlur(): void {\n this.onTouched();\n // Delay to allow click on dropdown\n setTimeout(() => this.isOpen.set(false), 200);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const flat = this.flatOptions();\n const total = flat.length + (this.showCreateOption() ? 1 : 0);\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.isOpen.set(true);\n if (total > 0) this.highlightedIndex.update((i) => (i + 1) % total);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (total > 0) this.highlightedIndex.update((i) => (i - 1 + total) % total);\n break;\n case 'Enter':\n event.preventDefault();\n if (this.highlightedIndex() >= 0) {\n if (this.highlightedIndex() === flat.length && this.showCreateOption()) {\n this.onCreateNew();\n } else {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n } else if (this.showCreateOption()) {\n this.onCreateNew();\n }\n break;\n case 'Escape':\n if (this.isOpen()) {\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n // Escape consumed by the list — an enclosing modal must not close too.\n event.stopPropagation();\n }\n break;\n case 'Tab':\n if (this.highlightedIndex() >= 0 && this.isOpen()) {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n this.isOpen.set(false);\n break;\n case 'Backspace':\n if (this.multiple() && !this.query() && this.selectedMultiple().length > 0) {\n this.removeSelected(this.selectedMultiple()[this.selectedMultiple().length - 1]);\n }\n break;\n }\n }\n\n protected selectOption(option: ComboboxOption): void {\n if (this.multiple()) {\n this.selectedMultiple.update((sel) => [...sel, option]);\n this.query.set('');\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n } else {\n this.selectedSingle.set(option);\n this.query.set(option.label);\n this.onChange(option);\n this.valueChange.emit(option);\n }\n this.optionSelected.emit(option);\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n }\n\n protected removeSelected(option: ComboboxOption): void {\n if (this.isDisabled()) return;\n this.selectedMultiple.update((sel) =>\n sel.filter((s) => s.value !== option.value)\n );\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onCreateNew(): void {\n const q = this.query().trim();\n if (!q) return;\n const newOption: ComboboxOption = { value: q, label: q };\n this.created.emit(q);\n this.selectOption(newOption);\n }\n\n @HostListener('document:click', ['$event'])\n protected onDocumentClick(event: MouseEvent): void {\n const target = event.target as Node | null;\n // The dropdown lives in the CDK overlay container, outside the host element.\n if (\n !this.elRef.nativeElement.contains(target) &&\n !this.dropdownEl()?.nativeElement.contains(target)\n ) {\n this.isOpen.set(false);\n }\n }\n}\n","<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <div #inputWrapper class=\"lc-combobox__input-wrapper\">\n <!-- Selected chips (multiple mode) -->\n @if (multiple()) {\n @for (sel of selectedMultiple(); track sel.value) {\n <lc-chip\n [removable]=\"!isDisabled()\"\n size=\"sm\"\n (remove)=\"removeSelected(sel)\"\n >{{ sel.label }}</lc-chip>\n }\n }\n\n <input\n #inputEl\n type=\"text\"\n class=\"lc-combobox__input\"\n [id]=\"inputId\"\n [placeholder]=\"multiple() && selectedMultiple().length > 0 ? '' : placeholder()\"\n [value]=\"query()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-invalid]=\"error() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (isLoading() || loading()) {\n <lc-spinner size=\"sm\" class=\"lc-combobox__spinner\" />\n } @else if (!multiple() && selectedSingle()) {\n <button\n type=\"button\"\n class=\"lc-combobox__clear\"\n [disabled]=\"isDisabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onClearClick()\"\n tabindex=\"-1\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" />\n </button>\n }\n </div>\n\n <!-- Dropdown: rendered in the CDK overlay container so overflow-hidden\n ancestors cannot clip it. Focus stays in the input (mousedown is\n prevented on the panel), keyboard nav uses aria-activedescendant. -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"inputWrapper\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayMatchWidth]=\"true\"\n (detach)=\"isOpen.set(false)\"\n >\n <div\n #dropdownEl\n class=\"lc-combobox__dropdown\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-multiselectable]=\"multiple() ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n >\n @for (group of groupedOptions(); track group.label) {\n @if (group.label) {\n <div class=\"lc-combobox__group-header\" role=\"presentation\">{{ group.label }}</div>\n }\n @for (option of group.items; track option.value) {\n @let idx = flatOptions().indexOf(option);\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option\"\n [class.lc-combobox__option--highlighted]=\"idx === highlightedIndex()\"\n [class.lc-combobox__option--disabled]=\"option.disabled\"\n role=\"option\"\n [id]=\"optionId(idx)\"\n [attr.aria-selected]=\"idx === highlightedIndex()\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"!option.disabled && selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(idx)\"\n >\n @if (option.icon) {\n <lc-icon [name]=\"option.icon\" size=\"sm\" class=\"lc-combobox__option-icon\" />\n }\n <div class=\"lc-combobox__option-content\">\n <span class=\"lc-combobox__option-label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"lc-combobox__option-desc\">{{ option.description }}</span>\n }\n </div>\n </div>\n }\n }\n\n @if (showCreateOption()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option lc-combobox__option--create\"\n [class.lc-combobox__option--highlighted]=\"highlightedIndex() === flatOptions().length\"\n role=\"option\"\n [id]=\"createOptionId\"\n [attr.aria-selected]=\"highlightedIndex() === flatOptions().length\"\n (click)=\"onCreateNew()\"\n (mouseenter)=\"highlightedIndex.set(flatOptions().length)\"\n >\n <lc-icon name=\"plus\" size=\"sm\" />\n <span>{{ createOptionLabel() }} \"{{ query() }}\"</span>\n </div>\n }\n\n @if (visibleOptions().length === 0 && !showCreateOption() && !isLoading() && !loading()) {\n <div class=\"lc-combobox__empty\">{{ emptyMessage() }}</div>\n }\n </div>\n </ng-template>\n\n @if (helperText() && !error()) {\n <span class=\"lc-combobox__helper\" [id]=\"inputId + '-helper'\">{{ helperText() }}</span>\n }\n @if (error()) {\n <span class=\"lc-combobox__error\" [id]=\"inputId + '-error'\" role=\"alert\">{{ error() }}</span>\n }\n</div>\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-combobox.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.ts","../../../../libs/angular-ui-kit/src/lib/combobox/combobox.component.html"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n afterRenderEffect,\n forwardRef,\n ElementRef,\n viewChild,\n HostListener,\n inject,\n untracked,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport { Observable, Subject, catchError, debounce, defer, of, switchMap, timer } from 'rxjs';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_PLUS, ICON_X_MARK } from '@lifecorner/angular-ui-kit/icons';\nimport { SpinnerComponent } from '@lifecorner/angular-ui-kit/spinner';\nimport { ChipComponent } from '@lifecorner/angular-ui-kit/chip';\n\nexport interface ComboboxOption {\n value: string;\n label: string;\n description?: string;\n icon?: string;\n group?: string;\n disabled?: boolean;\n}\n\nexport type ComboboxValue = ComboboxOption | ComboboxOption[] | null;\n\nexport type ComboboxSize = 'xs' | 'sm' | 'md' | 'lg';\n\n/**\n * Combobox / async autocomplete component.\n *\n * Supports free-text input with sync/async option suggestions,\n * single/multiple selection, create new entries, and keyboard navigation.\n * The suggestion list is rendered in a CDK overlay so it is never clipped\n * by `overflow: hidden` ancestors (cards, modals, table cells).\n *\n * @example\n * ```html\n * <lc-combobox\n * label=\"Assign to user\"\n * [loadOptions]=\"searchUsers\"\n * [(value)]=\"assignee\"\n * allowCreate\n * />\n * ```\n */\n@Component({\n selector: 'lc-combobox',\n standalone: true,\n imports: [OverlayModule, IconComponent, SpinnerComponent, ChipComponent],\n viewProviders: [ɵprovideKitIcons([ICON_X_MARK, ICON_PLUS])],\n templateUrl: './combobox.component.html',\n styleUrls: ['./combobox.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => ComboboxComponent),\n multi: true,\n },\n ],\n})\nexport class ComboboxComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance ids so label/listbox/options can be linked via ARIA */\n readonly inputId = `lc-combobox-${++ComboboxComponent.nextId}`;\n readonly listboxId = `${this.inputId}-listbox`;\n protected readonly createOptionId = `${this.listboxId}-create`;\n\n private readonly inputEl = viewChild<ElementRef<HTMLInputElement>>('inputEl');\n private readonly dropdownEl = viewChild<ElementRef<HTMLElement>>('dropdownEl');\n\n private readonly elRef = inject(ElementRef);\n private readonly querySubject = new Subject<string>();\n\n /** Sync options */\n readonly options = input<ComboboxOption[]>([]);\n\n /** Async option loader */\n readonly loadOptions = input<((query: string) => Observable<ComboboxOption[]>)>();\n\n /** Debounce for async queries */\n readonly debounceMs = input<number>(250);\n\n /** Minimum characters before triggering search */\n readonly minChars = input<number>(1);\n\n /** Placeholder text */\n readonly placeholder = input<string>('Search…');\n\n /** Label */\n readonly label = input<string>();\n\n /** Helper text */\n readonly helperText = input<string>();\n\n /** Error message */\n readonly error = input<string>();\n\n /** Disabled state */\n readonly disabled = input<boolean>(false);\n\n /** Allow multiple selections */\n readonly multiple = input<boolean>(false);\n\n /** Allow creating new entries */\n readonly allowCreate = input<boolean>(false);\n\n /** Show loading spinner (controlled) */\n readonly loading = input<boolean>(false);\n\n /** Empty state message */\n readonly emptyMessage = input<string>('No results');\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear');\n\n /** Label before the query in the \"create\" option (`allowCreate`): `Create \"query\"`. */\n readonly createOptionLabel = input('Create');\n\n /** Size */\n readonly size = input<ComboboxSize>('md');\n\n /** Value change event */\n readonly valueChange = output<ComboboxValue>();\n\n /** Query change event */\n readonly queryChange = output<string>();\n\n /** Option selected event */\n readonly optionSelected = output<ComboboxOption>();\n\n /** Created event (allowCreate) */\n readonly created = output<string>();\n\n /** Internal state */\n protected query = signal('');\n protected isOpen = signal(false);\n protected highlightedIndex = signal(-1);\n protected asyncOptions = signal<ComboboxOption[]>([]);\n protected isLoading = signal(false);\n\n /** Disabled via `setDisabledState` (reactive forms) */\n private readonly formDisabled = signal(false);\n\n /** Effective disabled state: `disabled` input OR form control disabled */\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n /** Selected values */\n protected selectedSingle = signal<ComboboxOption | null>(null);\n protected selectedMultiple = signal<ComboboxOption[]>([]);\n\n /** Resolved visible options */\n protected visibleOptions = computed(() => {\n const q = this.query().toLowerCase();\n const loader = this.loadOptions();\n\n let opts: ComboboxOption[];\n if (loader) {\n opts = this.asyncOptions();\n } else {\n opts = this.options();\n if (q.length >= this.minChars()) {\n opts = opts.filter(\n (o) =>\n o.label.toLowerCase().includes(q) ||\n o.value.toLowerCase().includes(q) ||\n (o.description && o.description.toLowerCase().includes(q))\n );\n }\n }\n\n // Remove already selected in multiple mode\n if (this.multiple()) {\n const selected = new Set(this.selectedMultiple().map((s) => s.value));\n opts = opts.filter((o) => !selected.has(o.value));\n }\n\n return opts;\n });\n\n /** Grouped options */\n protected groupedOptions = computed(() => {\n const opts = this.visibleOptions();\n const groups = new Map<string, ComboboxOption[]>();\n\n for (const opt of opts) {\n const group = opt.group || '';\n if (!groups.has(group)) groups.set(group, []);\n groups.get(group)!.push(opt);\n }\n\n return Array.from(groups.entries()).map(([label, items]) => ({\n label,\n items,\n }));\n });\n\n /** Flat list for keyboard nav */\n protected flatOptions = computed(() => {\n return this.groupedOptions().flatMap((g) => g.items);\n });\n\n /** Whether to show \"Create\" option */\n protected showCreateOption = computed(() => {\n if (!this.allowCreate()) return false;\n const q = this.query().trim();\n if (!q) return false;\n const exact = this.visibleOptions().some(\n (o) => o.label.toLowerCase() === q.toLowerCase()\n );\n return !exact;\n });\n\n /** id of the highlighted option — announced via aria-activedescendant */\n protected readonly activeDescendantId = computed(() => {\n if (!this.isOpen()) return null;\n const i = this.highlightedIndex();\n if (i < 0) return null;\n if (i === this.flatOptions().length) {\n return this.showCreateOption() ? this.createOptionId : null;\n }\n return i < this.flatOptions().length ? this.optionId(i) : null;\n });\n\n /** ids referenced by aria-describedby (helper / error) */\n protected readonly describedBy = computed(() => {\n if (this.error()) return `${this.inputId}-error`;\n if (this.helperText()) return `${this.inputId}-helper`;\n return null;\n });\n\n /** Container classes */\n protected containerClasses = computed(() => {\n const classes = [`lc-combobox`, `lc-combobox--${this.size()}`];\n if (this.isDisabled()) classes.push('lc-combobox--disabled');\n if (this.error()) classes.push('lc-combobox--error');\n if (this.isOpen()) classes.push('lc-combobox--open');\n return classes.join(' ');\n });\n\n protected optionId(index: number): string {\n return `${this.listboxId}-opt-${index}`;\n }\n\n // ControlValueAccessor\n private onChange: (value: ComboboxValue) => void = () => { /* set by registerOnChange */ };\n private onTouched: () => void = () => { /* set by registerOnTouched */ };\n\n constructor() {\n // Async loading pipe. `debounce` (not `debounceTime`) reads the signal per\n // emission, so `debounceMs` is honoured after inputs are populated.\n this.querySubject\n .pipe(\n debounce(() => timer(this.debounceMs())),\n switchMap((q) => {\n const loader = this.loadOptions();\n if (!loader || q.length < this.minChars()) {\n return of([] as ComboboxOption[]);\n }\n this.isLoading.set(true);\n // `defer` turns a synchronously throwing loader into an error\n // notification; `catchError` keeps the pipe alive for the next query.\n return defer(() => loader(q)).pipe(catchError(() => of([] as ComboboxOption[])));\n }),\n takeUntilDestroyed()\n )\n .subscribe((results) => {\n this.asyncOptions.set(results);\n this.isLoading.set(false);\n });\n\n // Keep the highlighted option visible while navigating with the keyboard\n // (after render, so the option element exists in the overlay pane).\n afterRenderEffect(() => {\n const id = this.activeDescendantId();\n if (!id) return;\n untracked(() => {\n // ids are generated from a counter, so no CSS escaping is needed\n this.dropdownEl()\n ?.nativeElement.querySelector<HTMLElement>(`#${id}`)\n ?.scrollIntoView?.({ block: 'nearest' });\n });\n });\n }\n\n writeValue(value: ComboboxValue): void {\n if (this.multiple()) {\n this.selectedMultiple.set(Array.isArray(value) ? value : []);\n } else {\n const single = value && !Array.isArray(value) ? value : null;\n this.selectedSingle.set(single);\n this.query.set(single ? single.label : '');\n }\n }\n\n registerOnChange(fn: (value: ComboboxValue) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n if (isDisabled) this.isOpen.set(false);\n }\n\n /**\n * Clear the current selection and query. Emits `null` (single) or `[]`\n * (multiple) exactly once, like a user-initiated deselect.\n */\n clear(): void {\n this.query.set('');\n this.highlightedIndex.set(-1);\n this.isOpen.set(false);\n const value: ComboboxValue = this.multiple() ? [] : null;\n if (this.multiple()) {\n this.selectedMultiple.set([]);\n } else {\n this.selectedSingle.set(null);\n }\n this.onChange(value);\n this.valueChange.emit(value);\n }\n\n protected onClearClick(): void {\n if (this.isDisabled()) return;\n this.clear();\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onInputChange(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.query.set(value);\n this.queryChange.emit(value);\n this.highlightedIndex.set(-1);\n\n if (this.loadOptions()) {\n this.querySubject.next(value);\n }\n\n if (value.length >= this.minChars()) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputFocus(): void {\n if (this.query().length >= this.minChars() || this.options().length > 0) {\n this.isOpen.set(true);\n }\n }\n\n protected onInputBlur(): void {\n this.onTouched();\n // Delay to allow click on dropdown\n setTimeout(() => this.isOpen.set(false), 200);\n }\n\n protected onKeydown(event: KeyboardEvent): void {\n const flat = this.flatOptions();\n const total = flat.length + (this.showCreateOption() ? 1 : 0);\n\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n this.isOpen.set(true);\n if (total > 0) this.highlightedIndex.update((i) => (i + 1) % total);\n break;\n case 'ArrowUp':\n event.preventDefault();\n if (total > 0) this.highlightedIndex.update((i) => (i - 1 + total) % total);\n break;\n case 'Enter':\n event.preventDefault();\n if (this.highlightedIndex() >= 0) {\n if (this.highlightedIndex() === flat.length && this.showCreateOption()) {\n this.onCreateNew();\n } else {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n } else if (this.showCreateOption()) {\n this.onCreateNew();\n }\n break;\n case 'Escape':\n if (this.isOpen()) {\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n // Escape consumed by the list — an enclosing modal must not close too.\n event.stopPropagation();\n }\n break;\n case 'Tab':\n if (this.highlightedIndex() >= 0 && this.isOpen()) {\n const opt = flat[this.highlightedIndex()];\n if (opt && !opt.disabled) {\n this.selectOption(opt);\n }\n }\n this.isOpen.set(false);\n break;\n case 'Backspace':\n if (this.multiple() && !this.query() && this.selectedMultiple().length > 0) {\n this.removeSelected(this.selectedMultiple()[this.selectedMultiple().length - 1]);\n }\n break;\n }\n }\n\n protected selectOption(option: ComboboxOption): void {\n if (this.multiple()) {\n this.selectedMultiple.update((sel) => [...sel, option]);\n this.query.set('');\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n } else {\n this.selectedSingle.set(option);\n this.query.set(option.label);\n this.onChange(option);\n this.valueChange.emit(option);\n }\n this.optionSelected.emit(option);\n this.isOpen.set(false);\n this.highlightedIndex.set(-1);\n }\n\n protected removeSelected(option: ComboboxOption): void {\n if (this.isDisabled()) return;\n this.selectedMultiple.update((sel) =>\n sel.filter((s) => s.value !== option.value)\n );\n const value = this.selectedMultiple();\n this.onChange(value);\n this.valueChange.emit(value);\n this.inputEl()?.nativeElement.focus();\n }\n\n protected onCreateNew(): void {\n const q = this.query().trim();\n if (!q) return;\n const newOption: ComboboxOption = { value: q, label: q };\n this.created.emit(q);\n this.selectOption(newOption);\n }\n\n @HostListener('document:click', ['$event'])\n protected onDocumentClick(event: MouseEvent): void {\n const target = event.target as Node | null;\n // The dropdown lives in the CDK overlay container, outside the host element.\n if (\n !this.elRef.nativeElement.contains(target) &&\n !this.dropdownEl()?.nativeElement.contains(target)\n ) {\n this.isOpen.set(false);\n }\n }\n}\n","<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <div #inputWrapper class=\"lc-combobox__input-wrapper\">\n <!-- Selected chips (multiple mode) -->\n @if (multiple()) {\n @for (sel of selectedMultiple(); track sel.value) {\n <lc-chip\n [removable]=\"!isDisabled()\"\n size=\"sm\"\n (remove)=\"removeSelected(sel)\"\n >{{ sel.label }}</lc-chip>\n }\n }\n\n <input\n #inputEl\n type=\"text\"\n class=\"lc-combobox__input\"\n [id]=\"inputId\"\n [placeholder]=\"multiple() && selectedMultiple().length > 0 ? '' : placeholder()\"\n [value]=\"query()\"\n [disabled]=\"isDisabled()\"\n role=\"combobox\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? listboxId : null\"\n [attr.aria-activedescendant]=\"activeDescendantId()\"\n [attr.aria-invalid]=\"error() ? true : null\"\n [attr.aria-describedby]=\"describedBy()\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n autocomplete=\"off\"\n (input)=\"onInputChange($event)\"\n (focus)=\"onInputFocus()\"\n (blur)=\"onInputBlur()\"\n (keydown)=\"onKeydown($event)\"\n />\n\n @if (isLoading() || loading()) {\n <lc-spinner size=\"sm\" class=\"lc-combobox__spinner\" />\n } @else if (!multiple() && selectedSingle()) {\n <button\n type=\"button\"\n class=\"lc-combobox__clear\"\n [disabled]=\"isDisabled()\"\n (mousedown)=\"$event.preventDefault()\"\n (click)=\"onClearClick()\"\n tabindex=\"-1\"\n [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" />\n </button>\n }\n </div>\n\n <!-- Dropdown: rendered in the CDK overlay container so overflow-hidden\n ancestors cannot clip it. Focus stays in the input (mousedown is\n prevented on the panel), keyboard nav uses aria-activedescendant. -->\n <ng-template\n cdkConnectedOverlay\n [cdkConnectedOverlayOrigin]=\"inputWrapper\"\n [cdkConnectedOverlayOpen]=\"isOpen()\"\n [cdkConnectedOverlayMatchWidth]=\"true\"\n (detach)=\"isOpen.set(false)\"\n >\n <div\n #dropdownEl\n class=\"lc-combobox__dropdown\"\n role=\"listbox\"\n [id]=\"listboxId\"\n [attr.aria-multiselectable]=\"multiple() ? true : null\"\n (mousedown)=\"$event.preventDefault()\"\n >\n @for (group of groupedOptions(); track group.label) {\n @if (group.label) {\n <div class=\"lc-combobox__group-header\" role=\"presentation\">{{ group.label }}</div>\n }\n @for (option of group.items; track option.value) {\n @let idx = flatOptions().indexOf(option);\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option\"\n [class.lc-combobox__option--highlighted]=\"idx === highlightedIndex()\"\n [class.lc-combobox__option--disabled]=\"option.disabled\"\n role=\"option\"\n [id]=\"optionId(idx)\"\n [attr.aria-selected]=\"idx === highlightedIndex()\"\n [attr.aria-disabled]=\"option.disabled\"\n (click)=\"!option.disabled && selectOption(option)\"\n (mouseenter)=\"highlightedIndex.set(idx)\"\n >\n @if (option.icon) {\n <lc-icon [name]=\"option.icon\" size=\"sm\" class=\"lc-combobox__option-icon\" />\n }\n <div class=\"lc-combobox__option-content\">\n <span class=\"lc-combobox__option-label\">{{ option.label }}</span>\n @if (option.description) {\n <span class=\"lc-combobox__option-desc\">{{ option.description }}</span>\n }\n </div>\n </div>\n }\n }\n\n @if (showCreateOption()) {\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- listbox option: focus stays in the input, keyboard selection via aria-activedescendant -->\n <div\n class=\"lc-combobox__option lc-combobox__option--create\"\n [class.lc-combobox__option--highlighted]=\"highlightedIndex() === flatOptions().length\"\n role=\"option\"\n [id]=\"createOptionId\"\n [attr.aria-selected]=\"highlightedIndex() === flatOptions().length\"\n (click)=\"onCreateNew()\"\n (mouseenter)=\"highlightedIndex.set(flatOptions().length)\"\n >\n <lc-icon name=\"plus\" size=\"sm\" />\n <span>{{ createOptionLabel() }} \"{{ query() }}\"</span>\n </div>\n }\n\n @if (visibleOptions().length === 0 && !showCreateOption() && !isLoading() && !loading()) {\n <div class=\"lc-combobox__empty\">{{ emptyMessage() }}</div>\n }\n </div>\n </ng-template>\n\n @if (helperText() && !error()) {\n <span class=\"lc-combobox__helper\" [id]=\"inputId + '-helper'\">{{ helperText() }}</span>\n }\n @if (error()) {\n <span class=\"lc-combobox__error\" [id]=\"inputId + '-error'\" role=\"alert\">{{ error() }}</span>\n }\n</div>\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
2
|
import { ApplicationRef, ChangeDetectionStrategy, Component, EnvironmentInjector, Injectable, computed, createComponent, effect, inject, input, output, signal } from "@angular/core";
|
|
3
3
|
import { FormsModule } from "@angular/forms";
|
|
4
|
-
import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
|
|
4
|
+
import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
|
|
5
|
+
import { ICON_EXCLAMATION_CIRCLE, ICON_EXCLAMATION_TRIANGLE } from "@lifecorner/angular-ui-kit/icons";
|
|
5
6
|
import { ButtonComponent } from "@lifecorner/angular-ui-kit/button";
|
|
6
7
|
import { InputComponent } from "@lifecorner/angular-ui-kit/input";
|
|
7
8
|
import { ModalComponent } from "@lifecorner/angular-ui-kit/modal";
|
|
@@ -280,6 +281,7 @@ var ConfirmDialogComponent = class ConfirmDialogComponent {
|
|
|
280
281
|
]
|
|
281
282
|
}
|
|
282
283
|
],
|
|
284
|
+
viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],
|
|
283
285
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
284
286
|
});
|
|
285
287
|
};
|
|
@@ -300,6 +302,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
300
302
|
ModalComponent,
|
|
301
303
|
InputComponent
|
|
302
304
|
],
|
|
305
|
+
viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],
|
|
303
306
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
304
307
|
template: "<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n",
|
|
305
308
|
styles: [".lc-confirm__header{display:flex;align-items:center;gap:.5rem}.lc-confirm__header h2{margin:0;font-size:var(--font-size-lg, 1.125rem);font-weight:var(--font-weight-semibold, 600);color:var(--color-text-primary)}.lc-confirm__message{margin:0;color:var(--color-text-secondary, #4b5563);font-size:var(--font-size-sm, .875rem);line-height:1.6}.lc-confirm__preview{margin-top:1rem}.lc-confirm__preview:empty{display:none}.lc-confirm__require-text{margin-top:1rem}.lc-confirm__footer{display:flex;gap:.5rem;justify-content:flex-end}\n"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-confirm-dialog.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.ts","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.html","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm.service.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n effect,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\nimport { ModalComponent, ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport type ConfirmDialogVariant = 'default' | 'destructive' | 'warning';\n\n/** Size of the confirm and cancel buttons (`lg` = 48.5 px, a 44 px target). */\nexport type ConfirmDialogButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface RequireTextConfig {\n prompt: string;\n expected: string;\n}\n\n/**\n * Confirm dialog component for confirming user actions.\n *\n * Builds on `<lc-modal>` to provide a standardized confirmation pattern\n * with optional destructive variant and text-matching confirmation.\n *\n * The dialog is named by its title (`aria-labelledby`); `[slot='preview']`\n * shows what the action affects below the message; `confirmLoading` keeps the\n * dialog open with a busy confirm button while the action runs.\n *\n * @example\n * ```html\n * <lc-confirm-dialog\n * [open]=\"showConfirm()\"\n * variant=\"destructive\"\n * title=\"Delete project?\"\n * message=\"This cannot be undone.\"\n * (confirmed)=\"onDelete()\"\n * (cancelled)=\"showConfirm.set(false)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-confirm-dialog',\n standalone: true,\n imports: [FormsModule, IconComponent, ButtonComponent, ModalComponent, InputComponent],\n templateUrl: './confirm-dialog.component.html',\n styleUrls: ['./confirm-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ConfirmDialogComponent {\n private static nextId = 0;\n\n /** Whether the dialog is open */\n readonly open = input<boolean>(false);\n\n /** Dialog variant */\n readonly variant = input<ConfirmDialogVariant>('default');\n\n /** Dialog title */\n readonly title = input.required<string>();\n\n /** Dialog message */\n readonly message = input.required<string>();\n\n /** Confirm button label */\n readonly confirmLabel = input<string>('Confirm');\n\n /** Cancel button label */\n readonly cancelLabel = input<string>('Cancel');\n\n /** Icon name (auto-set by variant if not provided) */\n readonly icon = input<string>();\n\n /** Require text match to enable confirm */\n readonly requireText = input<RequireTextConfig>();\n\n /** Accessible name of the close button in the header. */\n readonly closeAriaLabel = input('Close modal');\n\n /**\n * Shows a spinner on the confirm button and blocks a second confirm while\n * the action runs; the app closes the dialog when it is done.\n * @default false\n */\n readonly confirmLoading = input<boolean>(false);\n\n /**\n * Size of the confirm and cancel buttons: `md` (3.2) or `lg` (48.5 px, the\n * 44 px touch target), or `sm`.\n * @default 'md'\n */\n readonly buttonSize = input<ConfirmDialogButtonSize>('md');\n\n /**\n * Where the dialog sits (passed to `lc-modal`): `center` (3.2), `auto` (a\n * bottom sheet below 640 px) or `sheet`.\n * @default 'center'\n */\n readonly placement = input<ModalPlacement>('center');\n\n /** Id of the title, which names the dialog. */\n protected readonly titleId = `lc-confirm-title-${++ConfirmDialogComponent.nextId}`;\n\n /** Emitted when user confirms */\n readonly confirmed = output<void>();\n\n /** Emitted when user cancels */\n readonly cancelled = output<void>();\n\n /** Internal text input value */\n protected inputValue = signal('');\n\n /** Resolved icon name */\n protected resolvedIcon = computed(() => {\n const icon = this.icon();\n if (icon) return icon;\n switch (this.variant()) {\n case 'destructive':\n return 'exclamation-triangle';\n case 'warning':\n return 'exclamation-circle';\n default:\n // Tabler name — 'question-mark-circle' has no alias and rendered a placeholder\n return 'help-circle';\n }\n });\n\n /** Resolved icon color */\n protected iconColor = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'var(--color-error-default)';\n case 'warning':\n return 'var(--color-warning-default)';\n default:\n return 'var(--color-primary-600)';\n }\n });\n\n /** Confirm button variant */\n protected confirmButtonVariant = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'primary';\n }\n });\n\n /** Whether confirm is allowed (text match check) */\n protected confirmAllowed = computed(() => {\n const req = this.requireText();\n if (!req) return true;\n return this.inputValue() === req.expected;\n });\n\n constructor() {\n // Reset input when dialog opens\n effect(() => {\n if (this.open()) {\n this.inputValue.set('');\n }\n });\n }\n\n /**\n * Confirm via button click or Enter inside the require-text input.\n * Enter is deliberately NOT handled on the whole dialog: the focus trap\n * lands on the close/cancel buttons first, and Enter there must activate\n * *that* button, never the (possibly destructive) confirm action.\n */\n protected onConfirm(): void {\n if (!this.confirmAllowed() || this.confirmLoading()) return;\n this.confirmed.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n\n protected onModalClose(): void {\n this.cancelled.emit();\n }\n\n protected onInputChange(value: string | number): void {\n this.inputValue.set(String(value));\n }\n}\n","<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n","import {\n Injectable,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n inject,\n} from '@angular/core';\nimport {\n ConfirmDialogButtonSize,\n ConfirmDialogComponent,\n ConfirmDialogVariant,\n RequireTextConfig,\n} from './confirm-dialog.component';\nimport type { ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport interface ConfirmOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: ConfirmDialogVariant;\n icon?: string;\n requireText?: RequireTextConfig;\n /** Accessible name of the close button (3.3). */\n closeAriaLabel?: string;\n /** Size of both buttons (3.3): `lg` for a 44 px touch target. */\n buttonSize?: ConfirmDialogButtonSize;\n /** `center`, `auto` (a bottom sheet below 640 px) or `sheet` (3.3). */\n placement?: ModalPlacement;\n}\n\n/**\n * Imperative confirm dialog service.\n *\n * @example\n * ```ts\n * const ok = await this.confirmService.confirm({\n * title: 'Delete item?',\n * message: 'This cannot be undone.',\n * });\n * if (ok) { ... }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfirmService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n\n /**\n * Show a confirmation dialog and return a promise that resolves\n * to true (confirmed) or false (cancelled).\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n // Create a host element\n const hostEl = document.createElement('div');\n document.body.appendChild(hostEl);\n\n const componentRef = createComponent(ConfirmDialogComponent, {\n hostElement: hostEl,\n environmentInjector: this.injector,\n });\n\n // Set inputs\n componentRef.setInput('open', true);\n componentRef.setInput('title', opts.title);\n componentRef.setInput('message', opts.message);\n if (opts.confirmLabel) componentRef.setInput('confirmLabel', opts.confirmLabel);\n if (opts.cancelLabel) componentRef.setInput('cancelLabel', opts.cancelLabel);\n if (opts.variant) componentRef.setInput('variant', opts.variant);\n if (opts.icon) componentRef.setInput('icon', opts.icon);\n if (opts.requireText) componentRef.setInput('requireText', opts.requireText);\n if (opts.closeAriaLabel) componentRef.setInput('closeAriaLabel', opts.closeAriaLabel);\n if (opts.buttonSize) componentRef.setInput('buttonSize', opts.buttonSize);\n if (opts.placement) componentRef.setInput('placement', opts.placement);\n\n const cleanup = () => {\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n hostEl.remove();\n };\n\n componentRef.instance.confirmed.subscribe(() => {\n cleanup();\n resolve(true);\n });\n\n componentRef.instance.cancelled.subscribe(() => {\n cleanup();\n resolve(false);\n });\n\n this.appRef.attachView(componentRef.hostView);\n });\n }\n\n /**\n * Show a destructive confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'destructive' })`.\n */\n destructive(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'destructive' });\n }\n\n /**\n * Show a warning confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'warning' })`.\n */\n warning(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'warning' });\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-confirm-dialog.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.ts","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm-dialog.component.html","../../../../libs/angular-ui-kit/src/lib/confirm-dialog/confirm.service.ts"],"sourcesContent":["import {\n Component,\n ChangeDetectionStrategy,\n input,\n output,\n signal,\n computed,\n effect,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_EXCLAMATION_CIRCLE, ICON_EXCLAMATION_TRIANGLE } from '@lifecorner/angular-ui-kit/icons';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\nimport { ModalComponent, ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport type ConfirmDialogVariant = 'default' | 'destructive' | 'warning';\n\n/** Size of the confirm and cancel buttons (`lg` = 48.5 px, a 44 px target). */\nexport type ConfirmDialogButtonSize = 'sm' | 'md' | 'lg';\n\nexport interface RequireTextConfig {\n prompt: string;\n expected: string;\n}\n\n/**\n * Confirm dialog component for confirming user actions.\n *\n * Builds on `<lc-modal>` to provide a standardized confirmation pattern\n * with optional destructive variant and text-matching confirmation.\n *\n * The dialog is named by its title (`aria-labelledby`); `[slot='preview']`\n * shows what the action affects below the message; `confirmLoading` keeps the\n * dialog open with a busy confirm button while the action runs.\n *\n * @example\n * ```html\n * <lc-confirm-dialog\n * [open]=\"showConfirm()\"\n * variant=\"destructive\"\n * title=\"Delete project?\"\n * message=\"This cannot be undone.\"\n * (confirmed)=\"onDelete()\"\n * (cancelled)=\"showConfirm.set(false)\"\n * />\n * ```\n */\n@Component({\n selector: 'lc-confirm-dialog',\n standalone: true,\n imports: [FormsModule, IconComponent, ButtonComponent, ModalComponent, InputComponent],\n viewProviders: [ɵprovideKitIcons([ICON_EXCLAMATION_TRIANGLE, ICON_EXCLAMATION_CIRCLE])],\n templateUrl: './confirm-dialog.component.html',\n styleUrls: ['./confirm-dialog.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ConfirmDialogComponent {\n private static nextId = 0;\n\n /** Whether the dialog is open */\n readonly open = input<boolean>(false);\n\n /** Dialog variant */\n readonly variant = input<ConfirmDialogVariant>('default');\n\n /** Dialog title */\n readonly title = input.required<string>();\n\n /** Dialog message */\n readonly message = input.required<string>();\n\n /** Confirm button label */\n readonly confirmLabel = input<string>('Confirm');\n\n /** Cancel button label */\n readonly cancelLabel = input<string>('Cancel');\n\n /** Icon name (auto-set by variant if not provided) */\n readonly icon = input<string>();\n\n /** Require text match to enable confirm */\n readonly requireText = input<RequireTextConfig>();\n\n /** Accessible name of the close button in the header. */\n readonly closeAriaLabel = input('Close modal');\n\n /**\n * Shows a spinner on the confirm button and blocks a second confirm while\n * the action runs; the app closes the dialog when it is done.\n * @default false\n */\n readonly confirmLoading = input<boolean>(false);\n\n /**\n * Size of the confirm and cancel buttons: `md` (3.2) or `lg` (48.5 px, the\n * 44 px touch target), or `sm`.\n * @default 'md'\n */\n readonly buttonSize = input<ConfirmDialogButtonSize>('md');\n\n /**\n * Where the dialog sits (passed to `lc-modal`): `center` (3.2), `auto` (a\n * bottom sheet below 640 px) or `sheet`.\n * @default 'center'\n */\n readonly placement = input<ModalPlacement>('center');\n\n /** Id of the title, which names the dialog. */\n protected readonly titleId = `lc-confirm-title-${++ConfirmDialogComponent.nextId}`;\n\n /** Emitted when user confirms */\n readonly confirmed = output<void>();\n\n /** Emitted when user cancels */\n readonly cancelled = output<void>();\n\n /** Internal text input value */\n protected inputValue = signal('');\n\n /** Resolved icon name */\n protected resolvedIcon = computed(() => {\n const icon = this.icon();\n if (icon) return icon;\n switch (this.variant()) {\n case 'destructive':\n return 'exclamation-triangle';\n case 'warning':\n return 'exclamation-circle';\n default:\n // Tabler name — 'question-mark-circle' has no alias and rendered a placeholder\n return 'help-circle';\n }\n });\n\n /** Resolved icon color */\n protected iconColor = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'var(--color-error-default)';\n case 'warning':\n return 'var(--color-warning-default)';\n default:\n return 'var(--color-primary-600)';\n }\n });\n\n /** Confirm button variant */\n protected confirmButtonVariant = computed(() => {\n switch (this.variant()) {\n case 'destructive':\n return 'danger';\n case 'warning':\n return 'warning';\n default:\n return 'primary';\n }\n });\n\n /** Whether confirm is allowed (text match check) */\n protected confirmAllowed = computed(() => {\n const req = this.requireText();\n if (!req) return true;\n return this.inputValue() === req.expected;\n });\n\n constructor() {\n // Reset input when dialog opens\n effect(() => {\n if (this.open()) {\n this.inputValue.set('');\n }\n });\n }\n\n /**\n * Confirm via button click or Enter inside the require-text input.\n * Enter is deliberately NOT handled on the whole dialog: the focus trap\n * lands on the close/cancel buttons first, and Enter there must activate\n * *that* button, never the (possibly destructive) confirm action.\n */\n protected onConfirm(): void {\n if (!this.confirmAllowed() || this.confirmLoading()) return;\n this.confirmed.emit();\n }\n\n protected onCancel(): void {\n this.cancelled.emit();\n }\n\n protected onModalClose(): void {\n this.cancelled.emit();\n }\n\n protected onInputChange(value: string | number): void {\n this.inputValue.set(String(value));\n }\n}\n","<lc-modal\n [open]=\"open()\"\n size=\"sm\"\n [placement]=\"placement()\"\n [showCloseButton]=\"true\"\n [closeAriaLabel]=\"closeAriaLabel()\"\n [ariaLabelledBy]=\"titleId\"\n (openChange)=\"$event ? null : onModalClose()\"\n>\n <div slot=\"header\">\n <div class=\"lc-confirm__header\">\n <lc-icon\n [name]=\"resolvedIcon()\"\n size=\"md\"\n [color]=\"iconColor()\"\n [decorative]=\"true\"\n />\n <h2 [id]=\"titleId\">{{ title() }}</h2>\n </div>\n </div>\n\n <div slot=\"body\">\n <p class=\"lc-confirm__message\">{{ message() }}</p>\n\n <div class=\"lc-confirm__preview\">\n <ng-content select=\"[slot='preview']\" />\n </div>\n\n @if (requireText(); as req) {\n <div class=\"lc-confirm__require-text\">\n <!-- lc-input renders the prompt as an associated <label for> -->\n <lc-input\n [label]=\"req.prompt\"\n [placeholder]=\"req.expected\"\n (valueChange)=\"onInputChange($event)\"\n (enterPressed)=\"onConfirm()\"\n />\n </div>\n }\n </div>\n\n <div slot=\"footer\" class=\"lc-confirm__footer\">\n <lc-button\n variant=\"ghost\"\n [size]=\"buttonSize()\"\n (clicked)=\"onCancel()\"\n >\n {{ cancelLabel() }}\n </lc-button>\n <lc-button\n [variant]=\"confirmButtonVariant()\"\n [size]=\"buttonSize()\"\n [disabled]=\"!confirmAllowed()\"\n [loading]=\"confirmLoading()\"\n (clicked)=\"onConfirm()\"\n >\n {{ confirmLabel() }}\n </lc-button>\n </div>\n</lc-modal>\n","import {\n Injectable,\n ApplicationRef,\n createComponent,\n EnvironmentInjector,\n inject,\n} from '@angular/core';\nimport {\n ConfirmDialogButtonSize,\n ConfirmDialogComponent,\n ConfirmDialogVariant,\n RequireTextConfig,\n} from './confirm-dialog.component';\nimport type { ModalPlacement } from '@lifecorner/angular-ui-kit/modal';\n\nexport interface ConfirmOptions {\n title: string;\n message: string;\n confirmLabel?: string;\n cancelLabel?: string;\n variant?: ConfirmDialogVariant;\n icon?: string;\n requireText?: RequireTextConfig;\n /** Accessible name of the close button (3.3). */\n closeAriaLabel?: string;\n /** Size of both buttons (3.3): `lg` for a 44 px touch target. */\n buttonSize?: ConfirmDialogButtonSize;\n /** `center`, `auto` (a bottom sheet below 640 px) or `sheet` (3.3). */\n placement?: ModalPlacement;\n}\n\n/**\n * Imperative confirm dialog service.\n *\n * @example\n * ```ts\n * const ok = await this.confirmService.confirm({\n * title: 'Delete item?',\n * message: 'This cannot be undone.',\n * });\n * if (ok) { ... }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class ConfirmService {\n private readonly appRef = inject(ApplicationRef);\n private readonly injector = inject(EnvironmentInjector);\n\n /**\n * Show a confirmation dialog and return a promise that resolves\n * to true (confirmed) or false (cancelled).\n */\n confirm(opts: ConfirmOptions): Promise<boolean> {\n return new Promise<boolean>((resolve) => {\n // Create a host element\n const hostEl = document.createElement('div');\n document.body.appendChild(hostEl);\n\n const componentRef = createComponent(ConfirmDialogComponent, {\n hostElement: hostEl,\n environmentInjector: this.injector,\n });\n\n // Set inputs\n componentRef.setInput('open', true);\n componentRef.setInput('title', opts.title);\n componentRef.setInput('message', opts.message);\n if (opts.confirmLabel) componentRef.setInput('confirmLabel', opts.confirmLabel);\n if (opts.cancelLabel) componentRef.setInput('cancelLabel', opts.cancelLabel);\n if (opts.variant) componentRef.setInput('variant', opts.variant);\n if (opts.icon) componentRef.setInput('icon', opts.icon);\n if (opts.requireText) componentRef.setInput('requireText', opts.requireText);\n if (opts.closeAriaLabel) componentRef.setInput('closeAriaLabel', opts.closeAriaLabel);\n if (opts.buttonSize) componentRef.setInput('buttonSize', opts.buttonSize);\n if (opts.placement) componentRef.setInput('placement', opts.placement);\n\n const cleanup = () => {\n this.appRef.detachView(componentRef.hostView);\n componentRef.destroy();\n hostEl.remove();\n };\n\n componentRef.instance.confirmed.subscribe(() => {\n cleanup();\n resolve(true);\n });\n\n componentRef.instance.cancelled.subscribe(() => {\n cleanup();\n resolve(false);\n });\n\n this.appRef.attachView(componentRef.hostView);\n });\n }\n\n /**\n * Show a destructive confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'destructive' })`.\n */\n destructive(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'destructive' });\n }\n\n /**\n * Show a warning confirmation dialog.\n * Shorthand for `confirm({ ...opts, variant: 'warning' })`.\n */\n warning(opts: Omit<ConfirmOptions, 'variant'>): Promise<boolean> {\n return this.confirm({ ...opts, variant: 'warning' });\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
2
|
import { ChangeDetectionStrategy, Component, DestroyRef, inject, input, output, signal, viewChild } from "@angular/core";
|
|
3
3
|
import { ButtonComponent } from "@lifecorner/angular-ui-kit/button";
|
|
4
|
-
import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
|
|
4
|
+
import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
|
|
5
|
+
import { ICON_CHECK } from "@lifecorner/angular-ui-kit/icons";
|
|
5
6
|
import { InputComponent } from "@lifecorner/angular-ui-kit/input";
|
|
6
7
|
const CONFIRMATION_MS = 2e3;
|
|
7
8
|
var CopyFieldComponent = class CopyFieldComponent {
|
|
@@ -201,6 +202,7 @@ var CopyFieldComponent = class CopyFieldComponent {
|
|
|
201
202
|
]
|
|
202
203
|
}
|
|
203
204
|
],
|
|
205
|
+
viewProviders: [ɵprovideKitIcons([ICON_CHECK])],
|
|
204
206
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
205
207
|
});
|
|
206
208
|
};
|
|
@@ -218,6 +220,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
218
220
|
ButtonComponent,
|
|
219
221
|
IconComponent
|
|
220
222
|
],
|
|
223
|
+
viewProviders: [ɵprovideKitIcons([ICON_CHECK])],
|
|
221
224
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
222
225
|
template: "<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n",
|
|
223
226
|
styles: [":host{display:block;width:100%}.lc-copy-field{position:relative;display:flex;gap:var(--lc-density-gap-sm, .5rem)}.lc-copy-field--stacked{flex-direction:column}.lc-copy-field--inline{flex-direction:row;align-items:flex-end}.lc-copy-field--inline .lc-copy-field__value{flex:1;min-width:0}.lc-copy-field--inline .lc-copy-field__action{flex:none}.lc-copy-field__live{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}\n"]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-copy-field.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.ts","../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\n\n/** `stacked`: the button below the value at full width (phones); `inline`: beside it. */\nexport type CopyFieldLayout = 'stacked' | 'inline';\n\n/** How long the button says \"Copied\" (ms). */\nconst CONFIRMATION_MS = 2000;\n\n/**\n * A value to copy — an invitation link, a token, a command: the value\n * read-only and wrapping (never clipped), a 48.5 px copy button, and one\n * polite announcement after copying. If the clipboard refuses, the value is\n * selected so the person can copy it by hand.\n *\n * @example\n * ```html\n * <lc-copy-field label=\"Einladungslink\" [value]=\"link\" copyLabel=\"Kopieren\"\n * copiedLabel=\"Kopiert\" copiedAnnouncement=\"Link kopiert\" />\n * ```\n */\n@Component({\n selector: 'lc-copy-field',\n imports: [InputComponent, ButtonComponent, IconComponent],\n templateUrl: './copy-field.component.html',\n styleUrl: './copy-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyFieldComponent {\n /** Label of the value (its accessible name). */\n readonly label = input<string>('');\n\n /** The value to copy. */\n readonly value = input<string>('');\n\n /** Help below the value. */\n readonly helperText = input<string>();\n\n /** `stacked` (default): button below at full width; `inline`: button beside the value. */\n readonly layout = input<CopyFieldLayout>('stacked');\n\n /** Show the clipboard (and, after copying, check) icon in the button. */\n readonly showIcon = input<boolean>(true);\n\n /** Button label. */\n readonly copyLabel = input('Copy');\n\n /** Button label for two seconds after copying. */\n readonly copiedLabel = input('Copied');\n\n /** Spoken once after copying (polite live region). */\n readonly copiedAnnouncement = input('Copied to the clipboard');\n\n /** Emitted with the value after it was copied. */\n readonly copied = output<string>();\n\n /** Emitted when the clipboard refused; the value is then selected for copying by hand. */\n readonly copyFailed = output<void>();\n\n protected readonly isCopied = signal(false);\n\n private readonly field = viewChild(InputComponent);\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copies the value; on refusal selects it instead. */\n async copy(): Promise<void> {\n const value = this.value();\n try {\n const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;\n if (!clipboard) throw new Error('Clipboard API unavailable');\n await clipboard.writeText(value);\n } catch {\n this.copyFailed.emit();\n this.field()?.focus();\n this.field()?.select();\n return;\n }\n this.isCopied.set(true);\n this.copied.emit(value);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.isCopied.set(false), CONFIRMATION_MS);\n }\n}\n","<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-copy-field.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.ts","../../../../libs/angular-ui-kit/src/lib/copy-field/copy-field.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n} from '@angular/core';\nimport { ButtonComponent } from '@lifecorner/angular-ui-kit/button';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CHECK } from '@lifecorner/angular-ui-kit/icons';\nimport { InputComponent } from '@lifecorner/angular-ui-kit/input';\n\n/** `stacked`: the button below the value at full width (phones); `inline`: beside it. */\nexport type CopyFieldLayout = 'stacked' | 'inline';\n\n/** How long the button says \"Copied\" (ms). */\nconst CONFIRMATION_MS = 2000;\n\n/**\n * A value to copy — an invitation link, a token, a command: the value\n * read-only and wrapping (never clipped), a 48.5 px copy button, and one\n * polite announcement after copying. If the clipboard refuses, the value is\n * selected so the person can copy it by hand.\n *\n * @example\n * ```html\n * <lc-copy-field label=\"Einladungslink\" [value]=\"link\" copyLabel=\"Kopieren\"\n * copiedLabel=\"Kopiert\" copiedAnnouncement=\"Link kopiert\" />\n * ```\n */\n@Component({\n selector: 'lc-copy-field',\n imports: [InputComponent, ButtonComponent, IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_CHECK])],\n templateUrl: './copy-field.component.html',\n styleUrl: './copy-field.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class CopyFieldComponent {\n /** Label of the value (its accessible name). */\n readonly label = input<string>('');\n\n /** The value to copy. */\n readonly value = input<string>('');\n\n /** Help below the value. */\n readonly helperText = input<string>();\n\n /** `stacked` (default): button below at full width; `inline`: button beside the value. */\n readonly layout = input<CopyFieldLayout>('stacked');\n\n /** Show the clipboard (and, after copying, check) icon in the button. */\n readonly showIcon = input<boolean>(true);\n\n /** Button label. */\n readonly copyLabel = input('Copy');\n\n /** Button label for two seconds after copying. */\n readonly copiedLabel = input('Copied');\n\n /** Spoken once after copying (polite live region). */\n readonly copiedAnnouncement = input('Copied to the clipboard');\n\n /** Emitted with the value after it was copied. */\n readonly copied = output<string>();\n\n /** Emitted when the clipboard refused; the value is then selected for copying by hand. */\n readonly copyFailed = output<void>();\n\n protected readonly isCopied = signal(false);\n\n private readonly field = viewChild(InputComponent);\n private timer: ReturnType<typeof setTimeout> | undefined;\n\n constructor() {\n inject(DestroyRef).onDestroy(() => clearTimeout(this.timer));\n }\n\n /** Copies the value; on refusal selects it instead. */\n async copy(): Promise<void> {\n const value = this.value();\n try {\n const clipboard = typeof navigator === 'undefined' ? undefined : navigator.clipboard;\n if (!clipboard) throw new Error('Clipboard API unavailable');\n await clipboard.writeText(value);\n } catch {\n this.copyFailed.emit();\n this.field()?.focus();\n this.field()?.select();\n return;\n }\n this.isCopied.set(true);\n this.copied.emit(value);\n clearTimeout(this.timer);\n this.timer = setTimeout(() => this.isCopied.set(false), CONFIRMATION_MS);\n }\n}\n","<div\n class=\"lc-copy-field\"\n [class.lc-copy-field--stacked]=\"layout() === 'stacked'\"\n [class.lc-copy-field--inline]=\"layout() === 'inline'\"\n>\n <div class=\"lc-copy-field__value\">\n <lc-input\n [label]=\"label()\"\n [value]=\"value()\"\n [helperText]=\"helperText()\"\n size=\"lg\"\n [readonly]=\"true\"\n [readonlyWrap]=\"true\"\n />\n </div>\n\n <div class=\"lc-copy-field__action\">\n <lc-button variant=\"outline\" size=\"lg\" [fullWidth]=\"layout() === 'stacked'\" (clicked)=\"copy()\">\n @if (showIcon()) {\n <lc-icon slot=\"icon-before\" [name]=\"isCopied() ? 'check' : 'clipboard-document'\" size=\"sm\" [decorative]=\"true\" />\n }\n {{ isCopied() ? copiedLabel() : copyLabel() }}\n </lc-button>\n </div>\n\n <span class=\"lc-copy-field__live\" role=\"status\" aria-live=\"polite\">{{ isCopied() ? copiedAnnouncement() : '' }}</span>\n</div>\n"],"mappings":"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"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
2
|
import { ChangeDetectionStrategy, Component, ElementRef, HostListener, afterRenderEffect, computed, forwardRef, inject, input, output, signal, untracked, viewChild } from "@angular/core";
|
|
3
3
|
import { NG_VALUE_ACCESSOR } from "@angular/forms";
|
|
4
|
-
import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
|
|
4
|
+
import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
|
|
5
|
+
import { ICON_CALENDAR } from "@lifecorner/angular-ui-kit/icons";
|
|
5
6
|
const REFERENCE_WEEK = Array.from({ length: 7 }, (_, i) => new Date(2024, 0, 1 + i));
|
|
6
7
|
var DateRangePickerComponent = class DateRangePickerComponent {
|
|
7
8
|
static nextId = 0;
|
|
@@ -341,6 +342,7 @@ var DateRangePickerComponent = class DateRangePickerComponent {
|
|
|
341
342
|
"strict"
|
|
342
343
|
]
|
|
343
344
|
}],
|
|
345
|
+
viewProviders: [ɵprovideKitIcons([ICON_CALENDAR])],
|
|
344
346
|
changeDetection: i0.ChangeDetectionStrategy.OnPush
|
|
345
347
|
});
|
|
346
348
|
};
|
|
@@ -355,6 +357,7 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
355
357
|
selector: "lc-date-range-picker",
|
|
356
358
|
standalone: true,
|
|
357
359
|
imports: [IconComponent],
|
|
360
|
+
viewProviders: [ɵprovideKitIcons([ICON_CALENDAR])],
|
|
358
361
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
359
362
|
providers: [{
|
|
360
363
|
provide: NG_VALUE_ACCESSOR,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-date-range-picker.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/date-range-picker/date-range-picker.component.ts","../../../../libs/angular-ui-kit/src/lib/date-range-picker/date-range-picker.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n HostListener,\n afterRenderEffect,\n computed,\n forwardRef,\n inject,\n input,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { IconComponent } from '@lifecorner/angular-ui-kit/icon';\n\nexport interface DateRange {\n start: Date | null;\n end: Date | null;\n}\n\n/** Monday..Sunday of a known week — only used to derive localised weekday names */\nconst REFERENCE_WEEK = Array.from({ length: 7 }, (_, i) => new Date(2024, 0, 1 + i));\n\n@Component({\n selector: 'lc-date-range-picker',\n standalone: true,\n imports: [IconComponent],\n templateUrl: './date-range-picker.component.html',\n styleUrls: ['./date-range-picker.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DateRangePickerComponent),\n multi: true,\n },\n ],\n})\nexport class DateRangePickerComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance ids for label ↔ trigger ↔ panel ARIA wiring */\n readonly triggerId = `lc-drp-${++DateRangePickerComponent.nextId}`;\n readonly labelId = `${this.triggerId}-label`;\n readonly valueId = `${this.triggerId}-value`;\n readonly panelId = `${this.triggerId}-panel`;\n\n private readonly elRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly triggerEl = viewChild<ElementRef<HTMLButtonElement>>('triggerEl');\n private readonly panelEl = viewChild<ElementRef<HTMLElement>>('panelEl');\n\n readonly label = input('');\n readonly placeholder = input('Select date range');\n readonly disabled = input(false);\n readonly minDate = input<Date | null>(null);\n readonly maxDate = input<Date | null>(null);\n /** BCP 47 locale for the displayed dates, month title and weekday headers */\n readonly locale = input('de-DE');\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear');\n\n /** Accessible name of the previous-month button. */\n readonly previousMonthAriaLabel = input('Previous month');\n\n /** Accessible name of the next-month button. */\n readonly nextMonthAriaLabel = input('Next month');\n\n readonly rangeChange = output<DateRange>();\n\n protected isOpen = signal(false);\n protected range = signal<DateRange>({ start: null, end: null });\n protected selecting = signal<'start' | 'end'>('start');\n protected hoveredDate = signal<Date | null>(null);\n protected viewingMonth = signal(new Date());\n\n /** Disabled via `setDisabledState` (reactive forms) */\n private readonly formDisabled = signal(false);\n\n /** Effective disabled state: `disabled` input OR form control disabled */\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n private onChange: (val: DateRange) => void = () => { /* set by registerOnChange */ };\n private onTouched: () => void = () => { /* set by registerOnTouched */ };\n\n protected readonly displayValue = computed(() => {\n const r = this.range();\n if (!r.start) return '';\n const locale = this.locale();\n const fmt = (d: Date) => d.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric' });\n if (!r.end) return fmt(r.start) + ' – …';\n return `${fmt(r.start)} – ${fmt(r.end)}`;\n });\n\n protected readonly monthLabel = computed(() => {\n const d = this.viewingMonth();\n return d.toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' });\n });\n\n /** Monday-first weekday headers in the configured locale (e.g. Mo…So / Mon…Sun) */\n protected readonly weekdays = computed(() => {\n const locale = this.locale();\n // some ICU builds abbreviate with a trailing period (\"Mo.\") — keep the compact form\n return REFERENCE_WEEK.map((d) => d.toLocaleDateString(locale, { weekday: 'short' }).replace(/\\.$/, ''));\n });\n\n protected readonly calendarDays = computed(() => {\n const viewing = this.viewingMonth();\n const locale = this.locale();\n const year = viewing.getFullYear();\n const month = viewing.getMonth();\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n\n let startDow = firstDay.getDay();\n if (startDow === 0) startDow = 7; // Monday = 1\n const prefixDays = startDow - 1;\n\n const days: { date: Date; inMonth: boolean; disabled: boolean; ariaLabel: string }[] = [];\n const push = (date: Date, inMonth: boolean) =>\n days.push({\n date,\n inMonth,\n disabled: this.isDateDisabled(date),\n ariaLabel: date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }),\n });\n\n for (let i = prefixDays; i > 0; i--) {\n push(new Date(year, month, 1 - i), false);\n }\n\n for (let d = 1; d <= lastDay.getDate(); d++) {\n push(new Date(year, month, d), true);\n }\n\n const remaining = 42 - days.length;\n for (let i = 1; i <= remaining; i++) {\n push(new Date(year, month + 1, i), false);\n }\n\n return days;\n });\n\n constructor() {\n // Move focus into the panel once it is rendered so keyboard users land on\n // the calendar instead of having to tab through the trigger's siblings.\n afterRenderEffect(() => {\n if (!this.isOpen()) return;\n untracked(() => {\n const panel = this.panelEl()?.nativeElement;\n if (!panel || panel.contains(document.activeElement)) return;\n const target =\n panel.querySelector<HTMLButtonElement>('.lc-drp__day--start:not(:disabled)') ??\n panel.querySelector<HTMLButtonElement>('.lc-drp__day--today:not(:disabled)') ??\n panel.querySelector<HTMLButtonElement>('.lc-drp__day:not(.lc-drp__day--outside):not(:disabled)');\n target?.focus();\n });\n });\n }\n\n writeValue(value: DateRange | null): void {\n this.range.set(value ?? { start: null, end: null });\n if (value?.start) {\n this.viewingMonth.set(new Date(value.start.getFullYear(), value.start.getMonth(), 1));\n }\n }\n\n registerOnChange(fn: (val: DateRange) => void): void { this.onChange = fn; }\n registerOnTouched(fn: () => void): void { this.onTouched = fn; }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n if (isDisabled) this.isOpen.set(false);\n }\n\n protected toggle(): void {\n if (this.isDisabled()) return;\n if (this.isOpen()) {\n this.close();\n return;\n }\n this.selecting.set('start');\n this.hoveredDate.set(null);\n this.isOpen.set(true);\n }\n\n protected close(): void {\n if (!this.isOpen()) return;\n this.isOpen.set(false);\n this.onTouched();\n // Return focus to the trigger when it was inside the (now removed) panel\n if (this.elRef.nativeElement.contains(document.activeElement)) {\n this.triggerEl()?.nativeElement.focus();\n }\n }\n\n /** Escape (from the trigger or anywhere in the panel) closes the picker */\n @HostListener('keydown', ['$event'])\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape' && this.isOpen()) {\n this.close();\n // consumed here — an enclosing modal/drawer must not close as well\n event.stopPropagation();\n event.preventDefault();\n }\n }\n\n @HostListener('document:click', ['$event'])\n protected onDocumentClick(event: MouseEvent): void {\n if (this.isOpen() && !this.elRef.nativeElement.contains(event.target as Node)) {\n this.close();\n }\n }\n\n protected prevMonth(): void {\n this.viewingMonth.update(d => new Date(d.getFullYear(), d.getMonth() - 1, 1));\n }\n\n protected nextMonth(): void {\n this.viewingMonth.update(d => new Date(d.getFullYear(), d.getMonth() + 1, 1));\n }\n\n protected selectDate(date: Date): void {\n if (this.isDateDisabled(date)) return;\n\n const current = this.range();\n if (this.selecting() === 'start') {\n this.range.set({ start: date, end: null });\n this.selecting.set('end');\n } else {\n if (date < current.start!) {\n this.range.set({ start: date, end: current.start });\n } else {\n this.range.set({ start: current.start, end: date });\n }\n this.selecting.set('start');\n this.emitRange();\n this.close();\n }\n }\n\n protected onDayHover(date: Date): void {\n if (this.selecting() === 'end') {\n this.hoveredDate.set(date);\n }\n }\n\n protected isStart(date: Date): boolean {\n return this.sameDay(date, this.range().start);\n }\n\n protected isEnd(date: Date): boolean {\n return this.sameDay(date, this.range().end);\n }\n\n protected isInRange(date: Date): boolean {\n const r = this.range();\n if (!r.start) return false;\n const end = r.end || this.hoveredDate();\n if (!end) return false;\n const s = Math.min(r.start.getTime(), end.getTime());\n const e = Math.max(r.start.getTime(), end.getTime());\n const t = date.getTime();\n return t > s && t < e;\n }\n\n protected isToday(date: Date): boolean {\n return this.sameDay(date, new Date());\n }\n\n protected clearRange(event: Event): void {\n event.stopPropagation();\n if (this.isDisabled()) return;\n this.range.set({ start: null, end: null });\n const r = { start: null, end: null };\n this.onChange(r);\n this.rangeChange.emit(r);\n }\n\n /** min/max are compared by calendar day — `minDate = new Date()` keeps today selectable */\n private isDateDisabled(date: Date): boolean {\n const min = this.minDate();\n const max = this.maxDate();\n const day = this.dayStamp(date);\n if (min && day < this.dayStamp(min)) return true;\n if (max && day > this.dayStamp(max)) return true;\n return false;\n }\n\n private dayStamp(d: Date): number {\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n }\n\n private sameDay(a: Date | null, b: Date | null): boolean {\n if (!a || !b) return false;\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n }\n\n private emitRange(): void {\n const r = this.range();\n this.onChange(r);\n this.rangeChange.emit(r);\n }\n}\n","@if (label()) {\n <label class=\"lc-drp__label\" [id]=\"labelId\" [for]=\"triggerId\">{{ label() }}</label>\n}\n\n<!-- The clear button must not be nested inside the trigger button, so the\n bordered \"field\" wraps both. -->\n<div class=\"lc-drp__field\" [class.lc-drp__field--disabled]=\"isDisabled()\">\n <button\n #triggerEl\n type=\"button\"\n class=\"lc-drp__trigger\"\n [id]=\"triggerId\"\n [class.lc-drp__trigger--disabled]=\"isDisabled()\"\n [disabled]=\"isDisabled()\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? panelId : null\"\n [attr.aria-labelledby]=\"label() ? labelId + ' ' + valueId : null\"\n (click)=\"toggle()\"\n >\n <lc-icon class=\"lc-drp__icon\" name=\"calendar\" size=\"sm\" [decorative]=\"true\" />\n <span class=\"lc-drp__value\" [id]=\"valueId\" [class.lc-drp__value--placeholder]=\"!displayValue()\">\n {{ displayValue() || placeholder() }}\n </span>\n </button>\n @if (displayValue() && !isDisabled()) {\n <button type=\"button\" class=\"lc-drp__clear\" (click)=\"clearRange($event)\" [attr.aria-label]=\"clearAriaLabel()\">×</button>\n }\n</div>\n\n@if (isOpen()) {\n <div\n #panelEl\n class=\"lc-drp__dropdown\"\n role=\"dialog\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label() || placeholder()\"\n >\n <div class=\"lc-drp__header\">\n <button type=\"button\" class=\"lc-drp__nav\" [attr.aria-label]=\"previousMonthAriaLabel()\" (click)=\"prevMonth()\">‹</button>\n <span class=\"lc-drp__month\" aria-live=\"polite\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"lc-drp__nav\" [attr.aria-label]=\"nextMonthAriaLabel()\" (click)=\"nextMonth()\">›</button>\n </div>\n\n <div class=\"lc-drp__weekdays\" aria-hidden=\"true\">\n @for (wd of weekdays(); track $index) {\n <span class=\"lc-drp__weekday\">{{ wd }}</span>\n }\n </div>\n\n <div class=\"lc-drp__grid\">\n @for (day of calendarDays(); track day.date.getTime()) {\n <button\n type=\"button\"\n class=\"lc-drp__day\"\n [class.lc-drp__day--outside]=\"!day.inMonth\"\n [class.lc-drp__day--disabled]=\"day.disabled\"\n [class.lc-drp__day--today]=\"isToday(day.date)\"\n [class.lc-drp__day--start]=\"isStart(day.date)\"\n [class.lc-drp__day--end]=\"isEnd(day.date)\"\n [class.lc-drp__day--in-range]=\"isInRange(day.date)\"\n [disabled]=\"day.disabled\"\n [attr.aria-label]=\"day.ariaLabel\"\n [attr.aria-pressed]=\"isStart(day.date) || isEnd(day.date)\"\n (click)=\"selectDate(day.date)\"\n (mouseenter)=\"onDayHover(day.date)\"\n >{{ day.date.getDate() }}</button>\n }\n </div>\n\n <div class=\"lc-drp__footer\">\n <span class=\"lc-drp__hint\" aria-live=\"polite\">\n @if (selecting() === 'start') { Select start date }\n @else { Select end date }\n </span>\n </div>\n </div>\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-date-range-picker.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/date-range-picker/date-range-picker.component.ts","../../../../libs/angular-ui-kit/src/lib/date-range-picker/date-range-picker.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n ElementRef,\n HostListener,\n afterRenderEffect,\n computed,\n forwardRef,\n inject,\n input,\n output,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\nimport { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { IconComponent, ɵprovideKitIcons } from '@lifecorner/angular-ui-kit/icon';\nimport { ICON_CALENDAR } from '@lifecorner/angular-ui-kit/icons';\n\nexport interface DateRange {\n start: Date | null;\n end: Date | null;\n}\n\n/** Monday..Sunday of a known week — only used to derive localised weekday names */\nconst REFERENCE_WEEK = Array.from({ length: 7 }, (_, i) => new Date(2024, 0, 1 + i));\n\n@Component({\n selector: 'lc-date-range-picker',\n standalone: true,\n imports: [IconComponent],\n viewProviders: [ɵprovideKitIcons([ICON_CALENDAR])],\n templateUrl: './date-range-picker.component.html',\n styleUrls: ['./date-range-picker.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => DateRangePickerComponent),\n multi: true,\n },\n ],\n})\nexport class DateRangePickerComponent implements ControlValueAccessor {\n private static nextId = 0;\n\n /** Per-instance ids for label ↔ trigger ↔ panel ARIA wiring */\n readonly triggerId = `lc-drp-${++DateRangePickerComponent.nextId}`;\n readonly labelId = `${this.triggerId}-label`;\n readonly valueId = `${this.triggerId}-value`;\n readonly panelId = `${this.triggerId}-panel`;\n\n private readonly elRef = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly triggerEl = viewChild<ElementRef<HTMLButtonElement>>('triggerEl');\n private readonly panelEl = viewChild<ElementRef<HTMLElement>>('panelEl');\n\n readonly label = input('');\n readonly placeholder = input('Select date range');\n readonly disabled = input(false);\n readonly minDate = input<Date | null>(null);\n readonly maxDate = input<Date | null>(null);\n /** BCP 47 locale for the displayed dates, month title and weekday headers */\n readonly locale = input('de-DE');\n\n /** Accessible name of the clear button. */\n readonly clearAriaLabel = input('Clear');\n\n /** Accessible name of the previous-month button. */\n readonly previousMonthAriaLabel = input('Previous month');\n\n /** Accessible name of the next-month button. */\n readonly nextMonthAriaLabel = input('Next month');\n\n readonly rangeChange = output<DateRange>();\n\n protected isOpen = signal(false);\n protected range = signal<DateRange>({ start: null, end: null });\n protected selecting = signal<'start' | 'end'>('start');\n protected hoveredDate = signal<Date | null>(null);\n protected viewingMonth = signal(new Date());\n\n /** Disabled via `setDisabledState` (reactive forms) */\n private readonly formDisabled = signal(false);\n\n /** Effective disabled state: `disabled` input OR form control disabled */\n protected readonly isDisabled = computed(() => this.disabled() || this.formDisabled());\n\n private onChange: (val: DateRange) => void = () => { /* set by registerOnChange */ };\n private onTouched: () => void = () => { /* set by registerOnTouched */ };\n\n protected readonly displayValue = computed(() => {\n const r = this.range();\n if (!r.start) return '';\n const locale = this.locale();\n const fmt = (d: Date) => d.toLocaleDateString(locale, { day: '2-digit', month: '2-digit', year: 'numeric' });\n if (!r.end) return fmt(r.start) + ' – …';\n return `${fmt(r.start)} – ${fmt(r.end)}`;\n });\n\n protected readonly monthLabel = computed(() => {\n const d = this.viewingMonth();\n return d.toLocaleDateString(this.locale(), { month: 'long', year: 'numeric' });\n });\n\n /** Monday-first weekday headers in the configured locale (e.g. Mo…So / Mon…Sun) */\n protected readonly weekdays = computed(() => {\n const locale = this.locale();\n // some ICU builds abbreviate with a trailing period (\"Mo.\") — keep the compact form\n return REFERENCE_WEEK.map((d) => d.toLocaleDateString(locale, { weekday: 'short' }).replace(/\\.$/, ''));\n });\n\n protected readonly calendarDays = computed(() => {\n const viewing = this.viewingMonth();\n const locale = this.locale();\n const year = viewing.getFullYear();\n const month = viewing.getMonth();\n const firstDay = new Date(year, month, 1);\n const lastDay = new Date(year, month + 1, 0);\n\n let startDow = firstDay.getDay();\n if (startDow === 0) startDow = 7; // Monday = 1\n const prefixDays = startDow - 1;\n\n const days: { date: Date; inMonth: boolean; disabled: boolean; ariaLabel: string }[] = [];\n const push = (date: Date, inMonth: boolean) =>\n days.push({\n date,\n inMonth,\n disabled: this.isDateDisabled(date),\n ariaLabel: date.toLocaleDateString(locale, { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' }),\n });\n\n for (let i = prefixDays; i > 0; i--) {\n push(new Date(year, month, 1 - i), false);\n }\n\n for (let d = 1; d <= lastDay.getDate(); d++) {\n push(new Date(year, month, d), true);\n }\n\n const remaining = 42 - days.length;\n for (let i = 1; i <= remaining; i++) {\n push(new Date(year, month + 1, i), false);\n }\n\n return days;\n });\n\n constructor() {\n // Move focus into the panel once it is rendered so keyboard users land on\n // the calendar instead of having to tab through the trigger's siblings.\n afterRenderEffect(() => {\n if (!this.isOpen()) return;\n untracked(() => {\n const panel = this.panelEl()?.nativeElement;\n if (!panel || panel.contains(document.activeElement)) return;\n const target =\n panel.querySelector<HTMLButtonElement>('.lc-drp__day--start:not(:disabled)') ??\n panel.querySelector<HTMLButtonElement>('.lc-drp__day--today:not(:disabled)') ??\n panel.querySelector<HTMLButtonElement>('.lc-drp__day:not(.lc-drp__day--outside):not(:disabled)');\n target?.focus();\n });\n });\n }\n\n writeValue(value: DateRange | null): void {\n this.range.set(value ?? { start: null, end: null });\n if (value?.start) {\n this.viewingMonth.set(new Date(value.start.getFullYear(), value.start.getMonth(), 1));\n }\n }\n\n registerOnChange(fn: (val: DateRange) => void): void { this.onChange = fn; }\n registerOnTouched(fn: () => void): void { this.onTouched = fn; }\n\n setDisabledState(isDisabled: boolean): void {\n this.formDisabled.set(isDisabled);\n if (isDisabled) this.isOpen.set(false);\n }\n\n protected toggle(): void {\n if (this.isDisabled()) return;\n if (this.isOpen()) {\n this.close();\n return;\n }\n this.selecting.set('start');\n this.hoveredDate.set(null);\n this.isOpen.set(true);\n }\n\n protected close(): void {\n if (!this.isOpen()) return;\n this.isOpen.set(false);\n this.onTouched();\n // Return focus to the trigger when it was inside the (now removed) panel\n if (this.elRef.nativeElement.contains(document.activeElement)) {\n this.triggerEl()?.nativeElement.focus();\n }\n }\n\n /** Escape (from the trigger or anywhere in the panel) closes the picker */\n @HostListener('keydown', ['$event'])\n protected onKeydown(event: KeyboardEvent): void {\n if (event.key === 'Escape' && this.isOpen()) {\n this.close();\n // consumed here — an enclosing modal/drawer must not close as well\n event.stopPropagation();\n event.preventDefault();\n }\n }\n\n @HostListener('document:click', ['$event'])\n protected onDocumentClick(event: MouseEvent): void {\n if (this.isOpen() && !this.elRef.nativeElement.contains(event.target as Node)) {\n this.close();\n }\n }\n\n protected prevMonth(): void {\n this.viewingMonth.update(d => new Date(d.getFullYear(), d.getMonth() - 1, 1));\n }\n\n protected nextMonth(): void {\n this.viewingMonth.update(d => new Date(d.getFullYear(), d.getMonth() + 1, 1));\n }\n\n protected selectDate(date: Date): void {\n if (this.isDateDisabled(date)) return;\n\n const current = this.range();\n if (this.selecting() === 'start') {\n this.range.set({ start: date, end: null });\n this.selecting.set('end');\n } else {\n if (date < current.start!) {\n this.range.set({ start: date, end: current.start });\n } else {\n this.range.set({ start: current.start, end: date });\n }\n this.selecting.set('start');\n this.emitRange();\n this.close();\n }\n }\n\n protected onDayHover(date: Date): void {\n if (this.selecting() === 'end') {\n this.hoveredDate.set(date);\n }\n }\n\n protected isStart(date: Date): boolean {\n return this.sameDay(date, this.range().start);\n }\n\n protected isEnd(date: Date): boolean {\n return this.sameDay(date, this.range().end);\n }\n\n protected isInRange(date: Date): boolean {\n const r = this.range();\n if (!r.start) return false;\n const end = r.end || this.hoveredDate();\n if (!end) return false;\n const s = Math.min(r.start.getTime(), end.getTime());\n const e = Math.max(r.start.getTime(), end.getTime());\n const t = date.getTime();\n return t > s && t < e;\n }\n\n protected isToday(date: Date): boolean {\n return this.sameDay(date, new Date());\n }\n\n protected clearRange(event: Event): void {\n event.stopPropagation();\n if (this.isDisabled()) return;\n this.range.set({ start: null, end: null });\n const r = { start: null, end: null };\n this.onChange(r);\n this.rangeChange.emit(r);\n }\n\n /** min/max are compared by calendar day — `minDate = new Date()` keeps today selectable */\n private isDateDisabled(date: Date): boolean {\n const min = this.minDate();\n const max = this.maxDate();\n const day = this.dayStamp(date);\n if (min && day < this.dayStamp(min)) return true;\n if (max && day > this.dayStamp(max)) return true;\n return false;\n }\n\n private dayStamp(d: Date): number {\n return new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime();\n }\n\n private sameDay(a: Date | null, b: Date | null): boolean {\n if (!a || !b) return false;\n return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();\n }\n\n private emitRange(): void {\n const r = this.range();\n this.onChange(r);\n this.rangeChange.emit(r);\n }\n}\n","@if (label()) {\n <label class=\"lc-drp__label\" [id]=\"labelId\" [for]=\"triggerId\">{{ label() }}</label>\n}\n\n<!-- The clear button must not be nested inside the trigger button, so the\n bordered \"field\" wraps both. -->\n<div class=\"lc-drp__field\" [class.lc-drp__field--disabled]=\"isDisabled()\">\n <button\n #triggerEl\n type=\"button\"\n class=\"lc-drp__trigger\"\n [id]=\"triggerId\"\n [class.lc-drp__trigger--disabled]=\"isDisabled()\"\n [disabled]=\"isDisabled()\"\n aria-haspopup=\"dialog\"\n [attr.aria-expanded]=\"isOpen()\"\n [attr.aria-controls]=\"isOpen() ? panelId : null\"\n [attr.aria-labelledby]=\"label() ? labelId + ' ' + valueId : null\"\n (click)=\"toggle()\"\n >\n <lc-icon class=\"lc-drp__icon\" name=\"calendar\" size=\"sm\" [decorative]=\"true\" />\n <span class=\"lc-drp__value\" [id]=\"valueId\" [class.lc-drp__value--placeholder]=\"!displayValue()\">\n {{ displayValue() || placeholder() }}\n </span>\n </button>\n @if (displayValue() && !isDisabled()) {\n <button type=\"button\" class=\"lc-drp__clear\" (click)=\"clearRange($event)\" [attr.aria-label]=\"clearAriaLabel()\">×</button>\n }\n</div>\n\n@if (isOpen()) {\n <div\n #panelEl\n class=\"lc-drp__dropdown\"\n role=\"dialog\"\n [id]=\"panelId\"\n [attr.aria-label]=\"label() || placeholder()\"\n >\n <div class=\"lc-drp__header\">\n <button type=\"button\" class=\"lc-drp__nav\" [attr.aria-label]=\"previousMonthAriaLabel()\" (click)=\"prevMonth()\">‹</button>\n <span class=\"lc-drp__month\" aria-live=\"polite\">{{ monthLabel() }}</span>\n <button type=\"button\" class=\"lc-drp__nav\" [attr.aria-label]=\"nextMonthAriaLabel()\" (click)=\"nextMonth()\">›</button>\n </div>\n\n <div class=\"lc-drp__weekdays\" aria-hidden=\"true\">\n @for (wd of weekdays(); track $index) {\n <span class=\"lc-drp__weekday\">{{ wd }}</span>\n }\n </div>\n\n <div class=\"lc-drp__grid\">\n @for (day of calendarDays(); track day.date.getTime()) {\n <button\n type=\"button\"\n class=\"lc-drp__day\"\n [class.lc-drp__day--outside]=\"!day.inMonth\"\n [class.lc-drp__day--disabled]=\"day.disabled\"\n [class.lc-drp__day--today]=\"isToday(day.date)\"\n [class.lc-drp__day--start]=\"isStart(day.date)\"\n [class.lc-drp__day--end]=\"isEnd(day.date)\"\n [class.lc-drp__day--in-range]=\"isInRange(day.date)\"\n [disabled]=\"day.disabled\"\n [attr.aria-label]=\"day.ariaLabel\"\n [attr.aria-pressed]=\"isStart(day.date) || isEnd(day.date)\"\n (click)=\"selectDate(day.date)\"\n (mouseenter)=\"onDayHover(day.date)\"\n >{{ day.date.getDate() }}</button>\n }\n </div>\n\n <div class=\"lc-drp__footer\">\n <span class=\"lc-drp__hint\" aria-live=\"polite\">\n @if (selecting() === 'start') { Select start date }\n @else { Select end date }\n </span>\n </div>\n </div>\n}\n"],"mappings":";;;;;AAyBA,MAAM,iBAAiB,MAAM,KAAK,EAAE,QAAQ,EAAC,IAAK,GAAG,MAAM,IAAI,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC;AAkBnF,IAAa,2BAAb,MAAa,yBAAwB;CAC3B,OAAO,SAAS;CAGf,YAAY,UAAU,EAAE,yBAAyB;CACjD,UAAU,GAAG,KAAK,UAAS;CAC3B,UAAU,GAAG,KAAK,UAAS;CAC3B,UAAU,GAAG,KAAK,UAAS;CAEnB,QAAQ,OAAgC,UAAU;CAClD,YAAY,UAAyC,aAAY,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CACjE,UAAU,UAAmC,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAE/D,QAAQ,MAAM,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACjB,cAAc,MAAM,qBAAoB,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACxC,WAAW,MAAM,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CACvB,UAAU,MAAmB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAClC,UAAU,MAAmB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAElC,SAAS,MAAM,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAGvB,iBAAiB,MAAM,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAG/B,yBAAyB,MAAM,kBAAiB,GAAA,YAAA,CAAA,EAAA,WAAA,yBAAA,CAAA,+BAAA,CAAA,CAAA;CAGhD,qBAAqB,MAAM,cAAa,GAAA,YAAA,CAAA,EAAA,WAAA,qBAAA,CAAA,+BAAA,CAAA,CAAA;CAExC,cAAc,OAAM;CAEnB,SAAS,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACtB,QAAQ,OAAkB;EAAE,OAAO;EAAM,KAAK;CAAI,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CACrD,YAAY,OAAwB,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAC5C,cAAc,OAAoB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CACvC,eAAe,uBAAO,IAAI,KAAI,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAG1B,eAAe,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAG1B,aAAa,eAAe,KAAK,SAAQ,KAAM,KAAK,aAAY,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAE9E,iBAA0C,CAAiC;CAC3E,kBAA6B,CAAkC;CAEpD,eAAe,eAAc;EAC9C,MAAM,IAAI,KAAK,MAAK;EACpB,IAAI,CAAC,EAAE,OAAO,OAAO;EACrB,MAAM,SAAS,KAAK,OAAM;EAC1B,MAAM,OAAO,MAAY,EAAE,mBAAmB,QAAQ;GAAE,KAAK;GAAW,OAAO;GAAW,MAAM;EAAS,CAAE;EAC3G,IAAI,CAAC,EAAE,KAAK,OAAO,IAAI,EAAE,KAAK,IAAI;EAClC,OAAO,GAAG,IAAI,EAAE,KAAK,EAAC,KAAM,IAAI,EAAE,GAAG;CACvC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAEiB,aAAa,eAAc;EAE5C,OADU,KAAK,aACR,CAAA,CAAE,mBAAmB,KAAK,OAAM,GAAI;GAAE,OAAO;GAAQ,MAAM;EAAS,CAAE;CAC/E,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAGiB,WAAW,eAAc;EAC1C,MAAM,SAAS,KAAK,OAAM;EAE1B,OAAO,eAAe,KAAK,MAAM,EAAE,mBAAmB,QAAQ,EAAE,SAAS,QAAO,CAAE,CAAC,CAAC,QAAQ,OAAO,EAAE,CAAC;CACxG,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAEiB,eAAe,eAAc;EAC9C,MAAM,UAAU,KAAK,aAAY;EACjC,MAAM,SAAS,KAAK,OAAM;EAC1B,MAAM,OAAO,QAAQ,YAAW;EAChC,MAAM,QAAQ,QAAQ,SAAQ;EAC9B,MAAM,WAAW,IAAI,KAAK,MAAM,OAAO,CAAC;EACxC,MAAM,UAAU,IAAI,KAAK,MAAM,QAAQ,GAAG,CAAC;EAE3C,IAAI,WAAW,SAAS,OAAM;EAC9B,IAAI,aAAa,GAAG,WAAW;EAC/B,MAAM,aAAa,WAAW;EAE9B,MAAM,OAAiF,CAAA;EACvF,MAAM,QAAQ,MAAY,YACxB,KAAK,KAAK;GACR;GACA;GACA,UAAU,KAAK,eAAe,IAAI;GAClC,WAAW,KAAK,mBAAmB,QAAQ;IAAE,SAAS;IAAQ,KAAK;IAAW,OAAO;IAAQ,MAAM;GAAS,CAAE;EAC/G,CAAA;EAEH,KAAK,IAAI,IAAI,YAAY,IAAI,GAAG,KAC9B,KAAK,IAAI,KAAK,MAAM,OAAO,IAAI,CAAC,GAAG,KAAK;EAG1C,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,QAAO,GAAI,KACtC,KAAK,IAAI,KAAK,MAAM,OAAO,CAAC,GAAG,IAAI;EAGrC,MAAM,YAAY,KAAK,KAAK;EAC5B,KAAK,IAAI,IAAI,GAAG,KAAK,WAAW,KAC9B,KAAK,IAAI,KAAK,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK;EAG1C,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAEF,cAAA;EAGE,wBAAuB;GACrB,IAAI,CAAC,KAAK,OAAM,GAAI;GACpB,gBAAe;IACb,MAAM,QAAQ,KAAK,QAAO,CAAE,EAAE;IAC9B,IAAI,CAAC,SAAS,MAAM,SAAS,SAAS,aAAa,GAAG;IAKtD,CAHE,MAAM,cAAiC,oCAAoC,KAC3E,MAAM,cAAiC,oCAAoC,KAC3E,MAAM,cAAiC,wDAAwD,EACjG,EAAQ,MAAK;GACf,CAAC;EACH,CAAC;CACH;CAEA,WAAW,OAAuB;EAChC,KAAK,MAAM,IAAI,SAAS;GAAE,OAAO;GAAM,KAAK;EAAI,CAAE;EAClD,IAAI,OAAO,OACT,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,MAAM,YAAW,GAAI,MAAM,MAAM,SAAQ,GAAI,CAAC,CAAC;CAExF;CAEA,iBAAiB,IAA4B;EAAU,KAAK,WAAW;CAAI;CAC3E,kBAAkB,IAAc;EAAU,KAAK,YAAY;CAAI;CAE/D,iBAAiB,YAAmB;EAClC,KAAK,aAAa,IAAI,UAAU;EAChC,IAAI,YAAY,KAAK,OAAO,IAAI,KAAK;CACvC;CAEU,SAAM;EACd,IAAI,KAAK,WAAU,GAAI;EACvB,IAAI,KAAK,OAAM,GAAI;GACjB,KAAK,MAAK;GACV;EACF;EACA,KAAK,UAAU,IAAI,OAAO;EAC1B,KAAK,YAAY,IAAI,IAAI;EACzB,KAAK,OAAO,IAAI,IAAI;CACtB;CAEU,QAAK;EACb,IAAI,CAAC,KAAK,OAAM,GAAI;EACpB,KAAK,OAAO,IAAI,KAAK;EACrB,KAAK,UAAS;EAEd,IAAI,KAAK,MAAM,cAAc,SAAS,SAAS,aAAa,GAC1D,KAAK,UAAS,CAAE,EAAE,cAAc,MAAK;CAEzC;CAIU,UAAU,OAAoB;EACtC,IAAI,MAAM,QAAQ,YAAY,KAAK,OAAM,GAAI;GAC3C,KAAK,MAAK;GAEV,MAAM,gBAAe;GACrB,MAAM,eAAc;EACtB;CACF;CAGU,gBAAgB,OAAiB;EACzC,IAAI,KAAK,OAAM,KAAM,CAAC,KAAK,MAAM,cAAc,SAAS,MAAM,MAAc,GAC1E,KAAK,MAAK;CAEd;CAEU,YAAS;EACjB,KAAK,aAAa,QAAO,MAAK,IAAI,KAAK,EAAE,YAAW,GAAI,EAAE,SAAQ,IAAK,GAAG,CAAC,CAAC;CAC9E;CAEU,YAAS;EACjB,KAAK,aAAa,QAAO,MAAK,IAAI,KAAK,EAAE,YAAW,GAAI,EAAE,SAAQ,IAAK,GAAG,CAAC,CAAC;CAC9E;CAEU,WAAW,MAAU;EAC7B,IAAI,KAAK,eAAe,IAAI,GAAG;EAE/B,MAAM,UAAU,KAAK,MAAK;EAC1B,IAAI,KAAK,UAAS,MAAO,SAAS;GAChC,KAAK,MAAM,IAAI;IAAE,OAAO;IAAM,KAAK;GAAI,CAAE;GACzC,KAAK,UAAU,IAAI,KAAK;EAC1B,OAAO;GACL,IAAI,OAAO,QAAQ,OACjB,KAAK,MAAM,IAAI;IAAE,OAAO;IAAM,KAAK,QAAQ;GAAK,CAAE;QAElD,KAAK,MAAM,IAAI;IAAE,OAAO,QAAQ;IAAO,KAAK;GAAI,CAAE;GAEpD,KAAK,UAAU,IAAI,OAAO;GAC1B,KAAK,UAAS;GACd,KAAK,MAAK;EACZ;CACF;CAEU,WAAW,MAAU;EAC7B,IAAI,KAAK,UAAS,MAAO,OACvB,KAAK,YAAY,IAAI,IAAI;CAE7B;CAEU,QAAQ,MAAU;EAC1B,OAAO,KAAK,QAAQ,MAAM,KAAK,MAAK,CAAE,CAAC,KAAK;CAC9C;CAEU,MAAM,MAAU;EACxB,OAAO,KAAK,QAAQ,MAAM,KAAK,MAAK,CAAE,CAAC,GAAG;CAC5C;CAEU,UAAU,MAAU;EAC5B,MAAM,IAAI,KAAK,MAAK;EACpB,IAAI,CAAC,EAAE,OAAO,OAAO;EACrB,MAAM,MAAM,EAAE,OAAO,KAAK,YAAW;EACrC,IAAI,CAAC,KAAK,OAAO;EACjB,MAAM,IAAI,KAAK,IAAI,EAAE,MAAM,QAAO,GAAI,IAAI,QAAO,CAAE;EACnD,MAAM,IAAI,KAAK,IAAI,EAAE,MAAM,QAAO,GAAI,IAAI,QAAO,CAAE;EACnD,MAAM,IAAI,KAAK,QAAO;EACtB,OAAO,IAAI,KAAK,IAAI;CACtB;CAEU,QAAQ,MAAU;EAC1B,OAAO,KAAK,QAAQ,sBAAM,IAAI,KAAI,CAAE;CACtC;CAEU,WAAW,OAAY;EAC/B,MAAM,gBAAe;EACrB,IAAI,KAAK,WAAU,GAAI;EACvB,KAAK,MAAM,IAAI;GAAE,OAAO;GAAM,KAAK;EAAI,CAAE;EACzC,MAAM,IAAI;GAAE,OAAO;GAAM,KAAK;EAAI;EAClC,KAAK,SAAS,CAAC;EACf,KAAK,YAAY,KAAK,CAAC;CACzB;CAGQ,eAAe,MAAU;EAC/B,MAAM,MAAM,KAAK,QAAO;EACxB,MAAM,MAAM,KAAK,QAAO;EACxB,MAAM,MAAM,KAAK,SAAS,IAAI;EAC9B,IAAI,OAAO,MAAM,KAAK,SAAS,GAAG,GAAG,OAAO;EAC5C,IAAI,OAAO,MAAM,KAAK,SAAS,GAAG,GAAG,OAAO;EAC5C,OAAO;CACT;CAEQ,SAAS,GAAO;EACtB,OAAO,IAAI,KAAK,EAAE,YAAW,GAAI,EAAE,SAAQ,GAAI,EAAE,QAAO,CAAE,CAAC,CAAC,QAAO;CACrE;CAEQ,QAAQ,GAAgB,GAAc;EAC5C,IAAI,CAAC,KAAK,CAAC,GAAG,OAAO;EACrB,OAAO,EAAE,YAAW,MAAO,EAAE,YAAW,KAAM,EAAE,SAAQ,MAAO,EAAE,SAAQ,KAAM,EAAE,QAAO,MAAO,EAAE,QAAO;CAC1G;CAEQ,YAAS;EACf,MAAM,IAAI,KAAK,MAAK;EACpB,KAAK,SAAS,CAAC;EACf,KAAK,YAAY,KAAK,CAAC;CACzB;CAxQW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAwB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAxB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAwB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;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,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,gBAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,wBAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,oBAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA,EAAA,aAAA,cAAA;EAAA,MAAA,EAAA,WAAA;GAAA,WAAA;GAAA,kBAAA;EAAA,EAAA;EAAA,WARxB,CACT;GACE,SAAS;GACT,aAAa,iBAAiB,wBAAwB;GACtD,OAAO;EACR,CACF;EAAA,aAAA,CAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,WAAA;GAAA,aAAA;GAAA,UAAA;EAAA,GAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,SAAA;GAAA,aAAA;GAAA,UAAA;EAAA,CAAA;EAAA,UAAA;EAAA,UCzCH;EA8EA,QAAA,CAAA,24HAAA;EAAA,cAAA,CAAA;GAAA,MAAA;GAAA,MDhDY;GAAa,UAAA;GAAA,QAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;IAAA;GAAA;EAAA,CAAA;EAAA,eACR,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;EAAC,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAYvC,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAwB,YAAA,CAAA;EAhBpC,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAsB,YACpB;GAAI,SACP,CAAC,aAAa;GAAC,eACT,CAAC,iBAAiB,CAAC,aAAa,CAAC,CAAC;GAAC,iBAGjC,wBAAwB;GAAM,WACpC,CACT;IACE,SAAS;IACT,aAAa,iBAAgB,wBAAyB;IACtD,OAAO;GACR,CACF;GAAA,UAAA;GAAA,QAAA,CAAA,24HAAA;EAAA,CAAA;CAYqE,CAAA;CAAA,sBAAA,CAAA;CAAA,gBAAA;EAAA,WAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAW,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CACnB,WAAS,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,OAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,UAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,QAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,gBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,wBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,oBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAA;EAAA,CAAA;EAAA,WAAA,CAAA;GAoJtE,MAAA;GAAa,MAAA,CAAA,WAAW,CAAC,QAAQ,CAAC;;;GAUlC,MAAA;GAAa,MAAA,CAAA,kBAAkB,CAAC,QAAQ,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
2
|
import { ChangeDetectionStrategy, Component, ElementRef, ViewEncapsulation, computed, effect, inject, input, signal, untracked } from "@angular/core";
|
|
3
3
|
import { DomSanitizer } from "@angular/platform-browser";
|
|
4
|
-
import { IconComponent } from "@lifecorner/angular-ui-kit/icon";
|
|
4
|
+
import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
|
|
5
|
+
import { ICON_EXCLAMATION_TRIANGLE, ICON_FILE, ICON_FILE_TEXT, ICON_PLUS } from "@lifecorner/angular-ui-kit/icons";
|
|
5
6
|
import { SpinnerComponent } from "@lifecorner/angular-ui-kit/spinner";
|
|
6
7
|
import { CodeBlockComponent } from "@lifecorner/angular-ui-kit/code-block";
|
|
7
8
|
import { MarkdownComponent } from "@lifecorner/angular-ui-kit/markdown";
|
|
@@ -523,6 +524,12 @@ var DocumentViewerComponent = class DocumentViewerComponent {
|
|
|
523
524
|
]
|
|
524
525
|
}
|
|
525
526
|
],
|
|
527
|
+
viewProviders: [ɵprovideKitIcons([
|
|
528
|
+
ICON_PLUS,
|
|
529
|
+
ICON_EXCLAMATION_TRIANGLE,
|
|
530
|
+
ICON_FILE,
|
|
531
|
+
ICON_FILE_TEXT
|
|
532
|
+
])],
|
|
526
533
|
changeDetection: i0.ChangeDetectionStrategy.OnPush,
|
|
527
534
|
encapsulation: i0.ViewEncapsulation.None
|
|
528
535
|
});
|
|
@@ -543,6 +550,12 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
543
550
|
CodeBlockComponent,
|
|
544
551
|
MarkdownComponent
|
|
545
552
|
],
|
|
553
|
+
viewProviders: [ɵprovideKitIcons([
|
|
554
|
+
ICON_PLUS,
|
|
555
|
+
ICON_EXCLAMATION_TRIANGLE,
|
|
556
|
+
ICON_FILE,
|
|
557
|
+
ICON_FILE_TEXT
|
|
558
|
+
])],
|
|
546
559
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
547
560
|
encapsulation: ViewEncapsulation.None,
|
|
548
561
|
host: {
|