@lifecorner/angular-ui-kit 3.30.1 → 3.30.2

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.
@@ -9,6 +9,7 @@ import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/ico
9
9
  import { ICON_PLUS, ICON_X_MARK } from "@lifecorner/angular-ui-kit/icons";
10
10
  import { SpinnerComponent } from "@lifecorner/angular-ui-kit/spinner";
11
11
  import { ChipComponent } from "@lifecorner/angular-ui-kit/chip";
12
+ import { closestLang } from "@lifecorner/angular-ui-kit/internal/a11y";
12
13
  var ComboboxComponent = class ComboboxComponent {
13
14
  static nextId = 0;
14
15
  inputId = `lc-combobox-${++ComboboxComponent.nextId}`;
@@ -46,6 +47,7 @@ var ComboboxComponent = class ComboboxComponent {
46
47
  isLoading = signal(false, ...ngDevMode ? [{ debugName: "isLoading" }] : /* istanbul ignore next */ []);
47
48
  formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
48
49
  isDisabled = computed(() => this.disabled() || this.formDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
50
+ panelLang = computed(() => this.isOpen() ? closestLang(this.elRef.nativeElement) : null, ...ngDevMode ? [{ debugName: "panelLang" }] : /* istanbul ignore next */ []);
49
51
  selectedSingle = signal(null, ...ngDevMode ? [{ debugName: "selectedSingle" }] : /* istanbul ignore next */ []);
50
52
  selectedMultiple = signal([], ...ngDevMode ? [{ debugName: "selectedMultiple" }] : /* istanbul ignore next */ []);
51
53
  seenSelectedValue = null;
@@ -464,7 +466,7 @@ var ComboboxComponent = class ComboboxComponent {
464
466
  isSignal: true
465
467
  }],
466
468
  ngImport: i0,
467
- template: "<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- pointer shortcut; the input is the keyboard target -->\n <div\n #inputWrapper\n class=\"lc-combobox__input-wrapper\"\n (mousedown)=\"onFrameMousedown($event)\"\n (click)=\"onFrameClick($event)\"\n >\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 [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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",
469
+ template: "<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- pointer shortcut; the input is the keyboard target -->\n <div\n #inputWrapper\n class=\"lc-combobox__input-wrapper\"\n (mousedown)=\"onFrameMousedown($event)\"\n (click)=\"onFrameClick($event)\"\n >\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 [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" [decorative]=\"true\" />\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 [attr.lang]=\"panelLang()\"\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\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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",
468
470
  styles: [".lc-combobox{display:flex;flex-direction:column;gap:.25rem;position:relative;font-family:var(--font-family-sans)}.lc-combobox__label{font-size:var(--font-size-sm, .875rem);font-weight:500;color:var(--color-text-primary);margin-bottom:.125rem}.lc-combobox__input-wrapper{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;border:1px solid var(--color-field-border);border-radius:var(--border-radius-md, .375rem);background-color:var(--color-surface-2);padding:.25rem .5rem;transition:border-color .15s,box-shadow .15s;cursor:text}.lc-combobox__input-wrapper:hover{border-color:var(--color-text-secondary)}.lc-combobox__input-wrapper:focus-within{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-combobox--error .lc-combobox__input-wrapper{border-color:var(--color-error-default)}.lc-combobox--error .lc-combobox__input-wrapper:focus-within{outline:2px solid var(--color-error-default);outline-offset:0;box-shadow:none}.lc-combobox--disabled .lc-combobox__input-wrapper{opacity:.6;cursor:not-allowed;background-color:var(--color-surface-muted)}.lc-combobox--disabled .lc-combobox__input-wrapper:hover{border-color:var(--color-border)}.lc-combobox__input{flex:1;min-width:80px;border:none;outline:none;background:transparent;color:var(--color-text-primary);font-family:inherit}.lc-combobox__input::placeholder{color:var(--color-text-tertiary)}.lc-combobox__input:disabled{cursor:not-allowed}.lc-combobox--xs .lc-combobox__input{font-size:var(--font-size-xs, .75rem);height:1.5rem}.lc-combobox--sm .lc-combobox__input{font-size:var(--font-size-sm, .875rem);height:1.75rem}.lc-combobox--md .lc-combobox__input{font-size:var(--font-size-base, 1rem);height:2rem}.lc-combobox--lg .lc-combobox__input{font-size:var(--font-size-lg, 1.125rem);height:2.75rem;margin-block:-.25rem}.lc-combobox__spinner{flex-shrink:0}.lc-combobox__clear{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;margin:-.125rem;padding:.125rem;border:none;background:transparent;background-clip:content-box;cursor:pointer;color:var(--color-text-tertiary);border-radius:calc(var(--border-radius-sm) + .125rem);flex-shrink:0}.lc-combobox__clear:hover:not(:disabled){color:var(--color-text-primary);background-color:var(--color-surface-hover)}.lc-combobox__clear:disabled{cursor:not-allowed}.lc-combobox__clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0}.lc-combobox--lg .lc-combobox__clear{margin-inline-start:.625rem}.lc-combobox--lg .lc-combobox__clear:before{content:\"\";position:absolute;inset:-.625rem -.375rem -.625rem -.875rem}.lc-combobox__dropdown{margin-top:.25rem;max-height:240px;overflow-y:auto;background-color:var(--color-surface-raised);border:1px solid var(--color-border-strong);border-radius:var(--border-radius-md, .375rem);box-shadow:var(--elevation-3)}.lc-combobox__group-header{padding:.375rem .75rem;font-size:var(--font-size-xs, .75rem);font-weight:600;color:var(--color-text-tertiary);text-transform:uppercase;letter-spacing:.05em;margin-top:.25rem}.lc-combobox__group-header:first-child{margin-top:0}.lc-combobox__option{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;cursor:pointer;transition:background-color .1s}.lc-combobox__option--highlighted{background-color:var(--color-surface-hover)}.lc-combobox__option--disabled{opacity:.5;cursor:not-allowed}.lc-combobox__option--create{color:var(--color-primary-600);font-weight:500;border-top:1px solid var(--color-divider)}.lc-combobox__option-icon{flex-shrink:0;color:var(--color-text-tertiary)}.lc-combobox__option-content{display:flex;flex-direction:column;min-width:0}.lc-combobox__option-label{font-size:var(--font-size-sm, .875rem);color:var(--color-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-combobox__option-desc{font-size:var(--font-size-xs, .75rem);color:var(--color-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-combobox__empty{padding:.75rem;text-align:center;color:var(--color-text-tertiary);font-size:var(--font-size-sm, .875rem)}.lc-combobox__helper{font-size:var(--font-size-xs, .75rem);color:var(--color-text-secondary)}.lc-combobox__error{font-size:var(--font-size-xs, .75rem);color:var(--color-text-error)}@media(forced-colors:active){.lc-combobox--error .lc-combobox__input-wrapper:focus-within{outline-color:Highlight}.lc-combobox__clear:focus-visible{outline-color:Highlight}}\n"],
469
471
  dependencies: [
470
472
  {
@@ -579,7 +581,7 @@ i0.ɵɵngDeclareClassMetadata({
579
581
  useExisting: forwardRef(() => ComboboxComponent),
580
582
  multi: true
581
583
  }],
582
- template: "<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- pointer shortcut; the input is the keyboard target -->\n <div\n #inputWrapper\n class=\"lc-combobox__input-wrapper\"\n (mousedown)=\"onFrameMousedown($event)\"\n (click)=\"onFrameClick($event)\"\n >\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 [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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",
584
+ template: "<div [class]=\"containerClasses()\">\n @if (label()) {\n <label class=\"lc-combobox__label\" [for]=\"inputId\">{{ label() }}</label>\n }\n\n <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- pointer shortcut; the input is the keyboard target -->\n <div\n #inputWrapper\n class=\"lc-combobox__input-wrapper\"\n (mousedown)=\"onFrameMousedown($event)\"\n (click)=\"onFrameClick($event)\"\n >\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 [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" [decorative]=\"true\" />\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 [attr.lang]=\"panelLang()\"\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\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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",
583
585
  styles: [".lc-combobox{display:flex;flex-direction:column;gap:.25rem;position:relative;font-family:var(--font-family-sans)}.lc-combobox__label{font-size:var(--font-size-sm, .875rem);font-weight:500;color:var(--color-text-primary);margin-bottom:.125rem}.lc-combobox__input-wrapper{display:flex;flex-wrap:wrap;align-items:center;gap:.25rem;border:1px solid var(--color-field-border);border-radius:var(--border-radius-md, .375rem);background-color:var(--color-surface-2);padding:.25rem .5rem;transition:border-color .15s,box-shadow .15s;cursor:text}.lc-combobox__input-wrapper:hover{border-color:var(--color-text-secondary)}.lc-combobox__input-wrapper:focus-within{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-combobox--error .lc-combobox__input-wrapper{border-color:var(--color-error-default)}.lc-combobox--error .lc-combobox__input-wrapper:focus-within{outline:2px solid var(--color-error-default);outline-offset:0;box-shadow:none}.lc-combobox--disabled .lc-combobox__input-wrapper{opacity:.6;cursor:not-allowed;background-color:var(--color-surface-muted)}.lc-combobox--disabled .lc-combobox__input-wrapper:hover{border-color:var(--color-border)}.lc-combobox__input{flex:1;min-width:80px;border:none;outline:none;background:transparent;color:var(--color-text-primary);font-family:inherit}.lc-combobox__input::placeholder{color:var(--color-text-tertiary)}.lc-combobox__input:disabled{cursor:not-allowed}.lc-combobox--xs .lc-combobox__input{font-size:var(--font-size-xs, .75rem);height:1.5rem}.lc-combobox--sm .lc-combobox__input{font-size:var(--font-size-sm, .875rem);height:1.75rem}.lc-combobox--md .lc-combobox__input{font-size:var(--font-size-base, 1rem);height:2rem}.lc-combobox--lg .lc-combobox__input{font-size:var(--font-size-lg, 1.125rem);height:2.75rem;margin-block:-.25rem}.lc-combobox__spinner{flex-shrink:0}.lc-combobox__clear{position:relative;display:inline-flex;align-items:center;justify-content:center;width:1.5rem;height:1.5rem;margin:-.125rem;padding:.125rem;border:none;background:transparent;background-clip:content-box;cursor:pointer;color:var(--color-text-tertiary);border-radius:calc(var(--border-radius-sm) + .125rem);flex-shrink:0}.lc-combobox__clear:hover:not(:disabled){color:var(--color-text-primary);background-color:var(--color-surface-hover)}.lc-combobox__clear:disabled{cursor:not-allowed}.lc-combobox__clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0}.lc-combobox--lg .lc-combobox__clear{margin-inline-start:.625rem}.lc-combobox--lg .lc-combobox__clear:before{content:\"\";position:absolute;inset:-.625rem -.375rem -.625rem -.875rem}.lc-combobox__dropdown{margin-top:.25rem;max-height:240px;overflow-y:auto;background-color:var(--color-surface-raised);border:1px solid var(--color-border-strong);border-radius:var(--border-radius-md, .375rem);box-shadow:var(--elevation-3)}.lc-combobox__group-header{padding:.375rem .75rem;font-size:var(--font-size-xs, .75rem);font-weight:600;color:var(--color-text-tertiary);text-transform:uppercase;letter-spacing:.05em;margin-top:.25rem}.lc-combobox__group-header:first-child{margin-top:0}.lc-combobox__option{display:flex;align-items:center;gap:.5rem;padding:.5rem .75rem;cursor:pointer;transition:background-color .1s}.lc-combobox__option--highlighted{background-color:var(--color-surface-hover)}.lc-combobox__option--disabled{opacity:.5;cursor:not-allowed}.lc-combobox__option--create{color:var(--color-primary-600);font-weight:500;border-top:1px solid var(--color-divider)}.lc-combobox__option-icon{flex-shrink:0;color:var(--color-text-tertiary)}.lc-combobox__option-content{display:flex;flex-direction:column;min-width:0}.lc-combobox__option-label{font-size:var(--font-size-sm, .875rem);color:var(--color-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-combobox__option-desc{font-size:var(--font-size-xs, .75rem);color:var(--color-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-combobox__empty{padding:.75rem;text-align:center;color:var(--color-text-tertiary);font-size:var(--font-size-sm, .875rem)}.lc-combobox__helper{font-size:var(--font-size-xs, .75rem);color:var(--color-text-secondary)}.lc-combobox__error{font-size:var(--font-size-xs, .75rem);color:var(--color-text-error)}@media(forced-colors:active){.lc-combobox--error .lc-combobox__input-wrapper:focus-within{outline-color:Highlight}.lc-combobox__clear:focus-visible{outline-color:Highlight}}\n"]
584
586
  }]
585
587
  }],
@@ -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 effect,\n forwardRef,\n ElementRef,\n viewChild,\n HostListener,\n inject,\n isDevMode,\n model,\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 * The selection is two-way bindable by an option's `value` string\n * (`[(selectedValue)]`, single mode), next to the `valueChange` output with\n * the option object and the forms binding.\n *\n * @example\n * ```html\n * <lc-combobox\n * label=\"Assign to user\"\n * [loadOptions]=\"searchUsers\"\n * [(selectedValue)]=\"assigneeId\"\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 /**\n * The `value` of the selected option, two-way (3.29, regeln row 2):\n * `[(selectedValue)]=\"month\"`. Shows the matching option's label (from\n * `options`, or the current selection); an unknown value shows an empty\n * field and is filled in when `options` with it arrive. Page writes\n * (including back to `null`) select or clear silently: no\n * `selectedValueChange`, no `valueChange`, no forms `onChange`. Every user\n * choice or clear emits `selectedValueChange`, next to the unchanged\n * `valueChange` (the option object). Single mode only: ignored with\n * `multiple` (a dev warning). Use it or a forms binding, not both.\n * @default null\n */\n readonly selectedValue = model<string | null>(null);\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 /** The last `selectedValue` the component applied or emitted: a different one is a page write. */\n private seenSelectedValue: string | null = null;\n\n /** A page-written `selectedValue` no option matched yet: selected silently once `options` hold it. */\n private pendingSelectedValue: string | null = null;\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 // `selectedValue` (3.29): a page write selects or clears silently; an\n // unknown value waits for `options` that hold it. The component's own\n // writes (user choice, clear) are already applied, so they are skipped.\n effect(() => {\n const value = this.selectedValue();\n const options = this.options();\n untracked(() => {\n if (value !== this.seenSelectedValue) {\n this.seenSelectedValue = value;\n if (!this.multiple()) {\n this.applySelectedValue(value, options);\n } else if (value !== null && isDevMode()) {\n console.warn('[lc-combobox] selectedValue is ignored with multiple');\n }\n } else if (this.pendingSelectedValue !== null && !this.multiple()) {\n this.applySelectedValue(this.pendingSelectedValue, options);\n }\n });\n });\n }\n\n /** Shows the option with `value` (or clears for `null`) without emitting anything. */\n private applySelectedValue(value: string | null, options: ComboboxOption[]): void {\n this.pendingSelectedValue = null;\n if (value === null) {\n this.selectedSingle.set(null);\n this.query.set('');\n return;\n }\n if (this.selectedSingle()?.value === value) return;\n const match = options.find((o) => o.value === value) ?? null;\n if (!match) this.pendingSelectedValue = value;\n this.selectedSingle.set(match);\n this.query.set(match ? match.label : '');\n }\n\n /** Emits a user's single choice or clear through `selectedValueChange` (not in `multiple` mode). */\n private emitSelectedValue(value: string | null): void {\n if (this.multiple()) return;\n this.pendingSelectedValue = null;\n this.seenSelectedValue = value;\n this.selectedValue.set(value);\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.pendingSelectedValue = 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 this.emitSelectedValue(null);\n }\n\n protected onClearClick(): void {\n if (this.isDisabled()) return;\n this.clear();\n this.inputEl()?.nativeElement.focus();\n }\n\n /** Whether a pointer event on the frame hit the input or a button in it (chip ×, clear). */\n private hitsFrameControl(event: MouseEvent): boolean {\n const target = event.target as Element | null;\n if (!target || target === this.inputEl()?.nativeElement) return true;\n const button = target.closest('button');\n return !!button && (event.currentTarget as Element).contains(button);\n }\n\n /**\n * 3.30 (request 047, regeln row 6): a press on the frame beside the input\n * and its buttons keeps focus where it is (no blur, so the list stays open).\n */\n protected onFrameMousedown(event: MouseEvent): void {\n if (!this.hitsFrameControl(event)) event.preventDefault();\n }\n\n /** A click on the frame beside the input and its buttons focuses the input. */\n protected onFrameClick(event: MouseEvent): void {\n if (this.isDisabled() || this.hitsFrameControl(event)) return;\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 this.emitSelectedValue(option.value);\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 <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- pointer shortcut; the input is the keyboard target -->\n <div\n #inputWrapper\n class=\"lc-combobox__input-wrapper\"\n (mousedown)=\"onFrameMousedown($event)\"\n (click)=\"onFrameClick($event)\"\n >\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 [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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 effect,\n forwardRef,\n ElementRef,\n viewChild,\n HostListener,\n inject,\n isDevMode,\n model,\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';\nimport { closestLang } from '@lifecorner/angular-ui-kit/internal/a11y';\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). The dropdown\n * takes the `lang` of the host's closest `[lang]` (3.30.2).\n *\n * The selection is two-way bindable by an option's `value` string\n * (`[(selectedValue)]`, single mode), next to the `valueChange` output with\n * the option object and the forms binding.\n *\n * @example\n * ```html\n * <lc-combobox\n * label=\"Assign to user\"\n * [loadOptions]=\"searchUsers\"\n * [(selectedValue)]=\"assigneeId\"\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 /**\n * The `value` of the selected option, two-way (3.29, regeln row 2):\n * `[(selectedValue)]=\"month\"`. Shows the matching option's label (from\n * `options`, or the current selection); an unknown value shows an empty\n * field and is filled in when `options` with it arrive. Page writes\n * (including back to `null`) select or clear silently: no\n * `selectedValueChange`, no `valueChange`, no forms `onChange`. Every user\n * choice or clear emits `selectedValueChange`, next to the unchanged\n * `valueChange` (the option object). Single mode only: ignored with\n * `multiple` (a dev warning). Use it or a forms binding, not both.\n * @default null\n */\n readonly selectedValue = model<string | null>(null);\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 /**\n * `lang` of the open dropdown (3.30.2, WCAG 3.1.2): the overlay renders under\n * `<body>`, so it takes the host's closest `[lang]`, else none. Read at every\n * opening; `null` while closed, so the server never reads the DOM.\n */\n protected readonly panelLang = computed(() => (this.isOpen() ? closestLang(this.elRef.nativeElement) : null));\n\n /** Selected values */\n protected selectedSingle = signal<ComboboxOption | null>(null);\n protected selectedMultiple = signal<ComboboxOption[]>([]);\n\n /** The last `selectedValue` the component applied or emitted: a different one is a page write. */\n private seenSelectedValue: string | null = null;\n\n /** A page-written `selectedValue` no option matched yet: selected silently once `options` hold it. */\n private pendingSelectedValue: string | null = null;\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 // `selectedValue` (3.29): a page write selects or clears silently; an\n // unknown value waits for `options` that hold it. The component's own\n // writes (user choice, clear) are already applied, so they are skipped.\n effect(() => {\n const value = this.selectedValue();\n const options = this.options();\n untracked(() => {\n if (value !== this.seenSelectedValue) {\n this.seenSelectedValue = value;\n if (!this.multiple()) {\n this.applySelectedValue(value, options);\n } else if (value !== null && isDevMode()) {\n console.warn('[lc-combobox] selectedValue is ignored with multiple');\n }\n } else if (this.pendingSelectedValue !== null && !this.multiple()) {\n this.applySelectedValue(this.pendingSelectedValue, options);\n }\n });\n });\n }\n\n /** Shows the option with `value` (or clears for `null`) without emitting anything. */\n private applySelectedValue(value: string | null, options: ComboboxOption[]): void {\n this.pendingSelectedValue = null;\n if (value === null) {\n this.selectedSingle.set(null);\n this.query.set('');\n return;\n }\n if (this.selectedSingle()?.value === value) return;\n const match = options.find((o) => o.value === value) ?? null;\n if (!match) this.pendingSelectedValue = value;\n this.selectedSingle.set(match);\n this.query.set(match ? match.label : '');\n }\n\n /** Emits a user's single choice or clear through `selectedValueChange` (not in `multiple` mode). */\n private emitSelectedValue(value: string | null): void {\n if (this.multiple()) return;\n this.pendingSelectedValue = null;\n this.seenSelectedValue = value;\n this.selectedValue.set(value);\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.pendingSelectedValue = 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 this.emitSelectedValue(null);\n }\n\n protected onClearClick(): void {\n if (this.isDisabled()) return;\n this.clear();\n this.inputEl()?.nativeElement.focus();\n }\n\n /** Whether a pointer event on the frame hit the input or a button in it (chip ×, clear). */\n private hitsFrameControl(event: MouseEvent): boolean {\n const target = event.target as Element | null;\n if (!target || target === this.inputEl()?.nativeElement) return true;\n const button = target.closest('button');\n return !!button && (event.currentTarget as Element).contains(button);\n }\n\n /**\n * 3.30 (request 047, regeln row 6): a press on the frame beside the input\n * and its buttons keeps focus where it is (no blur, so the list stays open).\n */\n protected onFrameMousedown(event: MouseEvent): void {\n if (!this.hitsFrameControl(event)) event.preventDefault();\n }\n\n /** A click on the frame beside the input and its buttons focuses the input. */\n protected onFrameClick(event: MouseEvent): void {\n if (this.isDisabled() || this.hitsFrameControl(event)) return;\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 this.emitSelectedValue(option.value);\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 <!-- eslint-disable-next-line @angular-eslint/template/click-events-have-key-events, @angular-eslint/template/interactive-supports-focus -- pointer shortcut; the input is the keyboard target -->\n <div\n #inputWrapper\n class=\"lc-combobox__input-wrapper\"\n (mousedown)=\"onFrameMousedown($event)\"\n (click)=\"onFrameClick($event)\"\n >\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 [attr.aria-label]=\"clearAriaLabel()\"\n >\n <lc-icon name=\"x-mark\" size=\"xs\" [decorative]=\"true\" />\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 [attr.lang]=\"panelLang()\"\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\" [decorative]=\"true\" />\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\" [decorative]=\"true\" />\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":";;;;;;;;;;;;AAgFA,IAAa,oBAAb,MAAa,kBAAiB;CACpB,OAAO,SAAS;CAGf,UAAU,eAAe,EAAE,kBAAkB;CAC7C,YAAY,GAAG,KAAK,QAAO;CACjB,iBAAiB,GAAG,KAAK,UAAS;CAEpC,UAAU,UAAwC,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAC5D,aAAa,UAAmC,cAAa,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAE7D,QAAQ,OAAO,UAAU;CACzB,eAAe,IAAI,QAAO;CAGlC,UAAU,MAAwB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAGrC,cAAc,MAA0D,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGxE,aAAa,MAAc,KAAI,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAG/B,WAAW,MAAc,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAG3B,cAAc,MAAc,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGtC,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAGvB,aAAa,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAG5B,QAAQ,MAAe,GAAA,YAAA,CAAA,QAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAGvB,WAAW,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAGhC,WAAW,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,WAAA,CAAA,+BAAA,CAAA,CAAA;CAGhC,cAAc,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGnC,UAAU,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAG/B,eAAe,MAAc,cAAa,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAG1C,iBAAiB,MAAM,SAAQ,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAG/B,oBAAoB,MAAM,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,oBAAA,CAAA,+BAAA,CAAA,CAAA;CAGnC,OAAO,MAAoB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAchC,gBAAgB,MAAqB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAG1C,cAAc,OAAM;CAGpB,cAAc,OAAM;CAGpB,iBAAiB,OAAM;CAGvB,UAAU,OAAM;CAGf,QAAQ,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAClB,SAAS,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CACtB,mBAAmB,OAAO,IAAG,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAC7B,eAAe,OAAyB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAC3C,YAAY,OAAO,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAGlB,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;CAOnE,YAAY,eAAgB,KAAK,OAAM,IAAK,YAAY,KAAK,MAAM,aAAa,IAAI,MAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAGnG,iBAAiB,OAA8B,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CACpD,mBAAmB,OAAyB,CAAA,GAAG,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAGjD,oBAAmC;CAGnC,uBAAsC;CAGpC,iBAAiB,eAAc;EACvC,MAAM,IAAI,KAAK,MAAK,CAAE,CAAC,YAAW;EAClC,MAAM,SAAS,KAAK,YAAW;EAE/B,IAAI;EACJ,IAAI,QACF,OAAO,KAAK,aAAY;OACnB;GACL,OAAO,KAAK,QAAO;GACnB,IAAI,EAAE,UAAU,KAAK,SAAQ,GAC3B,OAAO,KAAK,QACT,MACC,EAAE,MAAM,YAAW,CAAE,CAAC,SAAS,CAAC,KAChC,EAAE,MAAM,YAAW,CAAE,CAAC,SAAS,CAAC,KAC/B,EAAE,eAAe,EAAE,YAAY,YAAW,CAAE,CAAC,SAAS,CAAC,CAAE;EAGlE;EAGA,IAAI,KAAK,SAAQ,GAAI;GACnB,MAAM,WAAW,IAAI,IAAI,KAAK,iBAAgB,CAAE,CAAC,KAAK,MAAM,EAAE,KAAK,CAAC;GACpE,OAAO,KAAK,QAAQ,MAAM,CAAC,SAAS,IAAI,EAAE,KAAK,CAAC;EAClD;EAEA,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAGQ,iBAAiB,eAAc;EACvC,MAAM,OAAO,KAAK,eAAc;EAChC,MAAM,yBAAS,IAAI,IAAG;EAEtB,KAAK,MAAM,OAAO,MAAM;GACtB,MAAM,QAAQ,IAAI,SAAS;GAC3B,IAAI,CAAC,OAAO,IAAI,KAAK,GAAG,OAAO,IAAI,OAAO,CAAA,CAAE;GAC5C,OAAO,IAAI,KAAK,CAAE,CAAC,KAAK,GAAG;EAC7B;EAEA,OAAO,MAAM,KAAK,OAAO,QAAO,CAAE,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY;GAC3D;GACA;EACD,EAAC;CACJ,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,iBAAA,CAAA,+BAAA,CAAA,CAAA;CAGQ,cAAc,eAAc;EACpC,OAAO,KAAK,eAAc,CAAE,CAAC,SAAS,MAAM,EAAE,KAAK;CACrD,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGQ,mBAAmB,eAAc;EACzC,IAAI,CAAC,KAAK,YAAW,GAAI,OAAO;EAChC,MAAM,IAAI,KAAK,MAAK,CAAE,CAAC,KAAI;EAC3B,IAAI,CAAC,GAAG,OAAO;EAIf,OAAO,CAHO,KAAK,eAAc,CAAE,CAAC,MACjC,MAAM,EAAE,MAAM,YAAW,MAAO,EAAE,YAAW,CAExC;CACV,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAGiB,qBAAqB,eAAc;EACpD,IAAI,CAAC,KAAK,OAAM,GAAI,OAAO;EAC3B,MAAM,IAAI,KAAK,iBAAgB;EAC/B,IAAI,IAAI,GAAG,OAAO;EAClB,IAAI,MAAM,KAAK,YAAW,CAAE,CAAC,QAC3B,OAAO,KAAK,iBAAgB,IAAK,KAAK,iBAAiB;EAEzD,OAAO,IAAI,KAAK,YAAW,CAAE,CAAC,SAAS,KAAK,SAAS,CAAC,IAAI;CAC5D,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,qBAAA,CAAA,+BAAA,CAAA,CAAA;CAGiB,cAAc,eAAc;EAC7C,IAAI,KAAK,MAAK,GAAI,OAAO,GAAG,KAAK,QAAO;EACxC,IAAI,KAAK,WAAU,GAAI,OAAO,GAAG,KAAK,QAAO;EAC7C,OAAO;CACT,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,cAAA,CAAA,+BAAA,CAAA,CAAA;CAGQ,mBAAmB,eAAc;EACzC,MAAM,UAAU,CAAC,eAAe,gBAAgB,KAAK,KAAI,GAAI;EAC7D,IAAI,KAAK,WAAU,GAAI,QAAQ,KAAK,uBAAuB;EAC3D,IAAI,KAAK,MAAK,GAAI,QAAQ,KAAK,oBAAoB;EACnD,IAAI,KAAK,OAAM,GAAI,QAAQ,KAAK,mBAAmB;EACnD,OAAO,QAAQ,KAAK,GAAG;CACzB,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CAEQ,SAAS,OAAa;EAC9B,OAAO,GAAG,KAAK,UAAS,OAAQ;CAClC;CAGQ,iBAAgD,CAAiC;CACjF,kBAA6B,CAAkC;CAEvE,cAAA;EAGE,KAAK,aACF,KACC,eAAe,MAAM,KAAK,WAAU,CAAE,CAAC,GACvC,WAAW,MAAK;GACd,MAAM,SAAS,KAAK,YAAW;GAC/B,IAAI,CAAC,UAAU,EAAE,SAAS,KAAK,SAAQ,GACrC,OAAO,GAAG,CAAA,CAAsB;GAElC,KAAK,UAAU,IAAI,IAAI;GAGvB,OAAO,YAAY,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,iBAAiB,GAAG,CAAA,CAAsB,CAAC,CAAC;EACjF,CAAC,GACD,mBAAkB,CAAE,CACrB,CACA,WAAW,YAAW;GACrB,KAAK,aAAa,IAAI,OAAO;GAC7B,KAAK,UAAU,IAAI,KAAK;EAC1B,CAAC;EAIH,wBAAuB;GACrB,MAAM,KAAK,KAAK,mBAAkB;GAClC,IAAI,CAAC,IAAI;GACT,gBAAe;IAEb,KAAK,WAAU,CAAE,EACb,cAAc,cAA2B,IAAI,IAAI,CAAC,EAClD,iBAAiB,EAAE,OAAO,UAAS,CAAE;GAC3C,CAAC;EACH,CAAC;EAKD,aAAY;GACV,MAAM,QAAQ,KAAK,cAAa;GAChC,MAAM,UAAU,KAAK,QAAO;GAC5B,gBAAe;IACb,IAAI,UAAU,KAAK,mBAAmB;KACpC,KAAK,oBAAoB;KACzB,IAAI,CAAC,KAAK,SAAQ,GAChB,KAAK,mBAAmB,OAAO,OAAO;UACjC,IAAI,UAAU,QAAQ,UAAS,GACpC,QAAQ,KAAK,sDAAsD;IAEvE,OAAO,IAAI,KAAK,yBAAyB,QAAQ,CAAC,KAAK,SAAQ,GAC7D,KAAK,mBAAmB,KAAK,sBAAsB,OAAO;GAE9D,CAAC;EACH,CAAC;CACH;CAGQ,mBAAmB,OAAsB,SAAyB;EACxE,KAAK,uBAAuB;EAC5B,IAAI,UAAU,MAAM;GAClB,KAAK,eAAe,IAAI,IAAI;GAC5B,KAAK,MAAM,IAAI,EAAE;GACjB;EACF;EACA,IAAI,KAAK,eAAc,CAAE,EAAE,UAAU,OAAO;EAC5C,MAAM,QAAQ,QAAQ,MAAM,MAAM,EAAE,UAAU,KAAK,KAAK;EACxD,IAAI,CAAC,OAAO,KAAK,uBAAuB;EACxC,KAAK,eAAe,IAAI,KAAK;EAC7B,KAAK,MAAM,IAAI,QAAQ,MAAM,QAAQ,EAAE;CACzC;CAGQ,kBAAkB,OAAoB;EAC5C,IAAI,KAAK,SAAQ,GAAI;EACrB,KAAK,uBAAuB;EAC5B,KAAK,oBAAoB;EACzB,KAAK,cAAc,IAAI,KAAK;CAC9B;CAEA,WAAW,OAAoB;EAC7B,IAAI,KAAK,SAAQ,GACf,KAAK,iBAAiB,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAA,CAAE;OACtD;GACL,MAAM,SAAS,SAAS,CAAC,MAAM,QAAQ,KAAK,IAAI,QAAQ;GACxD,KAAK,uBAAuB;GAC5B,KAAK,eAAe,IAAI,MAAM;GAC9B,KAAK,MAAM,IAAI,SAAS,OAAO,QAAQ,EAAE;EAC3C;CACF;CAEA,iBAAiB,IAAkC;EACjD,KAAK,WAAW;CAClB;CAEA,kBAAkB,IAAc;EAC9B,KAAK,YAAY;CACnB;CAEA,iBAAiB,YAAmB;EAClC,KAAK,aAAa,IAAI,UAAU;EAChC,IAAI,YAAY,KAAK,OAAO,IAAI,KAAK;CACvC;CAMA,QAAK;EACH,KAAK,MAAM,IAAI,EAAE;EACjB,KAAK,iBAAiB,IAAI,EAAE;EAC5B,KAAK,OAAO,IAAI,KAAK;EACrB,MAAM,QAAuB,KAAK,SAAQ,IAAK,CAAA,IAAK;EACpD,IAAI,KAAK,SAAQ,GACf,KAAK,iBAAiB,IAAI,CAAA,CAAE;OAE5B,KAAK,eAAe,IAAI,IAAI;EAE9B,KAAK,SAAS,KAAK;EACnB,KAAK,YAAY,KAAK,KAAK;EAC3B,KAAK,kBAAkB,IAAI;CAC7B;CAEU,eAAY;EACpB,IAAI,KAAK,WAAU,GAAI;EACvB,KAAK,MAAK;EACV,KAAK,QAAO,CAAE,EAAE,cAAc,MAAK;CACrC;CAGQ,iBAAiB,OAAiB;EACxC,MAAM,SAAS,MAAM;EACrB,IAAI,CAAC,UAAU,WAAW,KAAK,QAAO,CAAE,EAAE,eAAe,OAAO;EAChE,MAAM,SAAS,OAAO,QAAQ,QAAQ;EACtC,OAAO,CAAC,CAAC,UAAW,MAAM,cAA0B,SAAS,MAAM;CACrE;CAMU,iBAAiB,OAAiB;EAC1C,IAAI,CAAC,KAAK,iBAAiB,KAAK,GAAG,MAAM,eAAc;CACzD;CAGU,aAAa,OAAiB;EACtC,IAAI,KAAK,WAAU,KAAM,KAAK,iBAAiB,KAAK,GAAG;EACvD,KAAK,QAAO,CAAE,EAAE,cAAc,MAAK;CACrC;CAEU,cAAc,OAAY;EAClC,MAAM,QAAS,MAAM,OAA4B;EACjD,KAAK,MAAM,IAAI,KAAK;EACpB,KAAK,YAAY,KAAK,KAAK;EAC3B,KAAK,iBAAiB,IAAI,EAAE;EAE5B,IAAI,KAAK,YAAW,GAClB,KAAK,aAAa,KAAK,KAAK;EAG9B,IAAI,MAAM,UAAU,KAAK,SAAQ,GAC/B,KAAK,OAAO,IAAI,IAAI;CAExB;CAEU,eAAY;EACpB,IAAI,KAAK,MAAK,CAAE,CAAC,UAAU,KAAK,SAAQ,KAAM,KAAK,QAAO,CAAE,CAAC,SAAS,GACpE,KAAK,OAAO,IAAI,IAAI;CAExB;CAEU,cAAW;EACnB,KAAK,UAAS;EAEd,iBAAiB,KAAK,OAAO,IAAI,KAAK,GAAG,GAAG;CAC9C;CAEU,UAAU,OAAoB;EACtC,MAAM,OAAO,KAAK,YAAW;EAC7B,MAAM,QAAQ,KAAK,UAAU,KAAK,iBAAgB,IAAK,IAAI;EAE3D,QAAQ,MAAM,KAAd;GACE,KAAK;IACH,MAAM,eAAc;IACpB,KAAK,OAAO,IAAI,IAAI;IACpB,IAAI,QAAQ,GAAG,KAAK,iBAAiB,QAAQ,OAAO,IAAI,KAAK,KAAK;IAClE;GACF,KAAK;IACH,MAAM,eAAc;IACpB,IAAI,QAAQ,GAAG,KAAK,iBAAiB,QAAQ,OAAO,IAAI,IAAI,SAAS,KAAK;IAC1E;GACF,KAAK;IACH,MAAM,eAAc;IACpB,IAAI,KAAK,iBAAgB,KAAM,GAAG;KAChC,IAAI,KAAK,iBAAgB,MAAO,KAAK,UAAU,KAAK,iBAAgB,GAClE,KAAK,YAAW;UACX;MACL,MAAM,MAAM,KAAK,KAAK,iBAAgB;MACtC,IAAI,OAAO,CAAC,IAAI,UACd,KAAK,aAAa,GAAG;KAEzB;IACF,OAAO,IAAI,KAAK,iBAAgB,GAC9B,KAAK,YAAW;IAElB;GACF,KAAK;IACH,IAAI,KAAK,OAAM,GAAI;KACjB,KAAK,OAAO,IAAI,KAAK;KACrB,KAAK,iBAAiB,IAAI,EAAE;KAE5B,MAAM,gBAAe;IACvB;IACA;GACF,KAAK;IACH,IAAI,KAAK,iBAAgB,KAAM,KAAK,KAAK,OAAM,GAAI;KACjD,MAAM,MAAM,KAAK,KAAK,iBAAgB;KACtC,IAAI,OAAO,CAAC,IAAI,UACd,KAAK,aAAa,GAAG;IAEzB;IACA,KAAK,OAAO,IAAI,KAAK;IACrB;GACF,KAAK,aACH,IAAI,KAAK,SAAQ,KAAM,CAAC,KAAK,MAAK,KAAM,KAAK,iBAAgB,CAAE,CAAC,SAAS,GACvE,KAAK,eAAe,KAAK,iBAAgB,CAAE,CAAC,KAAK,iBAAgB,CAAE,CAAC,SAAS,EAAE;EAGrF;CACF;CAEU,aAAa,QAAsB;EAC3C,IAAI,KAAK,SAAQ,GAAI;GACnB,KAAK,iBAAiB,QAAQ,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC;GACtD,KAAK,MAAM,IAAI,EAAE;GACjB,MAAM,QAAQ,KAAK,iBAAgB;GACnC,KAAK,SAAS,KAAK;GACnB,KAAK,YAAY,KAAK,KAAK;EAC7B,OAAO;GACL,KAAK,eAAe,IAAI,MAAM;GAC9B,KAAK,MAAM,IAAI,OAAO,KAAK;GAC3B,KAAK,SAAS,MAAM;GACpB,KAAK,YAAY,KAAK,MAAM;GAC5B,KAAK,kBAAkB,OAAO,KAAK;EACrC;EACA,KAAK,eAAe,KAAK,MAAM;EAC/B,KAAK,OAAO,IAAI,KAAK;EACrB,KAAK,iBAAiB,IAAI,EAAE;CAC9B;CAEU,eAAe,QAAsB;EAC7C,IAAI,KAAK,WAAU,GAAI;EACvB,KAAK,iBAAiB,QAAQ,QAC5B,IAAI,QAAQ,MAAM,EAAE,UAAU,OAAO,KAAK,CAAC;EAE7C,MAAM,QAAQ,KAAK,iBAAgB;EACnC,KAAK,SAAS,KAAK;EACnB,KAAK,YAAY,KAAK,KAAK;EAC3B,KAAK,QAAO,CAAE,EAAE,cAAc,MAAK;CACrC;CAEU,cAAW;EACnB,MAAM,IAAI,KAAK,MAAK,CAAE,CAAC,KAAI;EAC3B,IAAI,CAAC,GAAG;EACR,MAAM,YAA4B;GAAE,OAAO;GAAG,OAAO;EAAC;EACtD,KAAK,QAAQ,KAAK,CAAC;EACnB,KAAK,aAAa,SAAS;CAC7B;CAGU,gBAAgB,OAAiB;EACzC,MAAM,SAAS,MAAM;EAErB,IACE,CAAC,KAAK,MAAM,cAAc,SAAS,MAAM,KACzC,CAAC,KAAK,WAAU,CAAE,EAAE,cAAc,SAAS,MAAM,GAEjD,KAAK,OAAO,IAAI,KAAK;CAEzB;CA/eW,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAiB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAAjB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAiB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,SAAA;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,YAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,YAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,UAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,aAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,cAAA;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,mBAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,eAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,SAAA;GAAA,eAAA;GAAA,aAAA;GAAA,aAAA;GAAA,gBAAA;GAAA,SAAA;EAAA;EAAA,MAAA,EAAA,WAAA,EAAA,kBAAA,0BAAA,EAAA;EAAA,WARjB,CACT;GACE,SAAS;GACT,aAAa,iBAAiB,iBAAiB;GAC/C,OAAO;EACR,CACF;EAAA,aAAA,CAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,SAAA;GAAA,aAAA;GAAA,UAAA;EAAA,GAAA;GAAA,cAAA;GAAA,OAAA;GAAA,WAAA,CAAA,YAAA;GAAA,aAAA;GAAA,UAAA;EAAA,CAAA;EAAA,UAAA;EAAA,UC9EH;EA6IA,QAAA,CAAA,y4IAAA;EAAA,cAAA;GAAA;IAAA,MAAA;IAAA,MD1EY;GAAa;GAAA;IAAA,MAAA;IAAA,MAAA,GAAA;IAAA,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,UAAA,CAAA,qBAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAa,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAgB,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;IAAA;GAAA;GAAA;IAAA,MAAA;IAAA,MAAE;IAAa,UAAA;IAAA,QAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;KAAA;IAAA;IAAA,SAAA,CAAA,UAAA,WAAA;GAAA;EAAA;EAAA,eACxD,CAAC,iBAAiB,CAAC,aAAa,SAAS,CAAC,CAAC;EAAC,iBAAA,GAAA,wBAAA;CAAA,CAAA;;AAYhD,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAiB,YAAA,CAAA;EAhB7B,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAa,YACX;GAAI,SACP;IAAC;IAAe;IAAe;IAAkB;GAAa;GAAC,eACzD,CAAC,iBAAiB,CAAC,aAAa,SAAS,CAAC,CAAC;GAAC,iBAG1C,wBAAwB;GAAM,WACpC,CACT;IACE,SAAS;IACT,aAAa,iBAAgB,iBAAkB;IAC/C,OAAO;GACR,CACF;GAAA,UAAA;GAAA,QAAA,CAAA,y4IAAA;EAAA,CAAA;CAUkE,CAAA;CAAA,sBAAA,CAAA;CAAA,gBAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,WAAS,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CACX,cAAY,EAAA,UAAA,KAAA,CAAA;EAAA,CAAA;EAAA,SAAA,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,YAAA,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,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,OAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,YAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,OAAA,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,UAAA,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,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,cAAA,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,mBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,MAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,CAAA;EAAA,eAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA;IAAA,UAAA;IAAA,OAAA;IAAA,UAAA;GAAA,CAAA;EAAA,GAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,qBAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAA;EAAA,CAAA;EAAA,aAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,aAAA;EAAA,CAAA;EAAA,gBAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,gBAAA;EAAA,CAAA;EAAA,SAAA,CAAA;GAAA,MAAA,GAAA;GAAA,MAAA,CAAA,SAAA;EAAA,CAAA;EAAA,iBAAA,CAAA;GA4d5E,MAAA;GAAa,MAAA,CAAA,kBAAkB,CAAC,QAAQ,CAAC"}
@@ -3,6 +3,7 @@ import { ChangeDetectionStrategy, Component, ElementRef, HostListener, afterRend
3
3
  import { NG_VALUE_ACCESSOR } from "@angular/forms";
4
4
  import { IconComponent, ɵprovideKitIcons } from "@lifecorner/angular-ui-kit/icon";
5
5
  import { ICON_CALENDAR } from "@lifecorner/angular-ui-kit/icons";
6
+ import { closestLang } from "@lifecorner/angular-ui-kit/internal/a11y";
6
7
  const REFERENCE_WEEK = Array.from({ length: 7 }, (_, i) => new Date(2024, 0, 1 + i));
7
8
  var DateRangePickerComponent = class DateRangePickerComponent {
8
9
  static nextId = 0;
@@ -33,6 +34,7 @@ var DateRangePickerComponent = class DateRangePickerComponent {
33
34
  viewingMonth = signal(/* @__PURE__ */ new Date(), ...ngDevMode ? [{ debugName: "viewingMonth" }] : /* istanbul ignore next */ []);
34
35
  formDisabled = signal(false, ...ngDevMode ? [{ debugName: "formDisabled" }] : /* istanbul ignore next */ []);
35
36
  isDisabled = computed(() => this.disabled() || this.formDisabled(), ...ngDevMode ? [{ debugName: "isDisabled" }] : /* istanbul ignore next */ []);
37
+ panelLang = computed(() => this.isOpen() && closestLang(this.elRef.nativeElement) === null ? this.locale() || null : null, ...ngDevMode ? [{ debugName: "panelLang" }] : /* istanbul ignore next */ []);
36
38
  onChange = () => {};
37
39
  onTouched = () => {};
38
40
  displayValue = computed(() => {
@@ -326,7 +328,7 @@ var DateRangePickerComponent = class DateRangePickerComponent {
326
328
  isSignal: true
327
329
  }],
328
330
  ngImport: i0,
329
- template: "@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",
331
+ template: "@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 [attr.lang]=\"panelLang()\"\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",
330
332
  styles: [":host{display:block;position:relative}.lc-drp__label{display:block;margin-bottom:4px;font-size:var(--typography-font-size-sm, .875rem);font-weight:500;color:var(--color-text-secondary)}.lc-drp__field{display:flex;align-items:stretch;min-height:40px;border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);background:var(--color-surface-2);transition:border-color .15s,box-shadow .15s}.lc-drp__field:hover:not(.lc-drp__field--disabled):not(:focus-within){border-color:var(--color-text-secondary)}.lc-drp__field:focus-within{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-drp__field--disabled{opacity:.6;background:var(--color-surface-muted)}.lc-drp__trigger{flex:1;display:flex;align-items:center;gap:8px;min-width:0;padding:8px 12px;border:none;border-radius:inherit;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.lc-drp__trigger:focus{outline:none}.lc-drp__trigger--disabled,.lc-drp__trigger:disabled{cursor:not-allowed}.lc-drp__icon{flex-shrink:0;color:var(--color-text-tertiary);display:inline-flex}.lc-drp__value{flex:1;min-width:0;font-size:var(--typography-font-size-sm, .875rem);color:var(--color-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-drp__value--placeholder{color:var(--color-text-tertiary)}.lc-drp__clear{border:none;background:none;padding:0 8px;cursor:pointer;font-size:16px;color:var(--color-text-tertiary);border-radius:inherit}.lc-drp__clear:hover{color:var(--color-text-secondary)}.lc-drp__clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-drp__dropdown{position:absolute;z-index:100;top:100%;left:0;margin-top:4px;padding:12px;background-color:var(--color-surface);background-image:var(--gradient-surface);border:1px solid var(--color-border-strong);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-4);width:280px}.lc-drp__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.lc-drp__nav{width:28px;height:28px;border:none;border-radius:var(--border-radius-sm);background:transparent;cursor:pointer;font-size:18px;color:var(--color-text-secondary);display:flex;align-items:center;justify-content:center}.lc-drp__nav:hover{background:var(--color-surface-hover)}.lc-drp__nav:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0}.lc-drp__month{font-size:var(--typography-font-size-sm, .875rem);font-weight:600;color:var(--color-text-primary)}.lc-drp__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:0;margin-bottom:4px}.lc-drp__weekday{text-align:center;font-size:.6875rem;font-weight:600;color:var(--color-text-tertiary);padding:4px}.lc-drp__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:0}.lc-drp__day{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border:none;background:transparent;cursor:pointer;font-size:.75rem;border-radius:var(--border-radius-sm);color:var(--color-text-primary);transition:all .1s}.lc-drp__day:hover:not(:disabled){background:var(--color-surface-hover)}.lc-drp__day:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px;z-index:1}.lc-drp__day--outside{color:var(--color-text-tertiary)}.lc-drp__day--disabled{color:var(--color-text-disabled);cursor:default}.lc-drp__day--today{font-weight:700;box-shadow:inset 0 -2px 0 var(--color-primary-500)}.lc-drp__day--start,.lc-drp__day--end{background:var(--color-primary-fill)!important;color:var(--color-on-primary)!important;font-weight:600}.lc-drp__day--in-range{background:var(--color-surface-selected);border-radius:0}.lc-drp__day--start{border-radius:var(--border-radius-sm) 0 0 var(--border-radius-sm)}.lc-drp__day--end{border-radius:0 var(--border-radius-sm) var(--border-radius-sm) 0}.lc-drp__footer{margin-top:8px;padding-top:8px;border-top:1px solid var(--color-divider)}.lc-drp__hint{font-size:.6875rem;color:var(--color-text-tertiary)}\n"],
331
333
  dependencies: [{
332
334
  kind: "component",
@@ -364,7 +366,7 @@ i0.ɵɵngDeclareClassMetadata({
364
366
  useExisting: forwardRef(() => DateRangePickerComponent),
365
367
  multi: true
366
368
  }],
367
- template: "@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",
369
+ template: "@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 [attr.lang]=\"panelLang()\"\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",
368
370
  styles: [":host{display:block;position:relative}.lc-drp__label{display:block;margin-bottom:4px;font-size:var(--typography-font-size-sm, .875rem);font-weight:500;color:var(--color-text-secondary)}.lc-drp__field{display:flex;align-items:stretch;min-height:40px;border:1px solid var(--color-field-border);border-radius:var(--border-radius-md);background:var(--color-surface-2);transition:border-color .15s,box-shadow .15s}.lc-drp__field:hover:not(.lc-drp__field--disabled):not(:focus-within){border-color:var(--color-text-secondary)}.lc-drp__field:focus-within{border-color:var(--color-primary-500);box-shadow:0 0 0 3px color-mix(in srgb,var(--color-primary-500) 20%,transparent)}.lc-drp__field--disabled{opacity:.6;background:var(--color-surface-muted)}.lc-drp__trigger{flex:1;display:flex;align-items:center;gap:8px;min-width:0;padding:8px 12px;border:none;border-radius:inherit;background:transparent;color:inherit;font:inherit;text-align:left;cursor:pointer}.lc-drp__trigger:focus{outline:none}.lc-drp__trigger--disabled,.lc-drp__trigger:disabled{cursor:not-allowed}.lc-drp__icon{flex-shrink:0;color:var(--color-text-tertiary);display:inline-flex}.lc-drp__value{flex:1;min-width:0;font-size:var(--typography-font-size-sm, .875rem);color:var(--color-text-primary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.lc-drp__value--placeholder{color:var(--color-text-tertiary)}.lc-drp__clear{border:none;background:none;padding:0 8px;cursor:pointer;font-size:16px;color:var(--color-text-tertiary);border-radius:inherit}.lc-drp__clear:hover{color:var(--color-text-secondary)}.lc-drp__clear:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-drp__dropdown{position:absolute;z-index:100;top:100%;left:0;margin-top:4px;padding:12px;background-color:var(--color-surface);background-image:var(--gradient-surface);border:1px solid var(--color-border-strong);border-radius:var(--border-radius-lg);box-shadow:var(--elevation-4);width:280px}.lc-drp__header{display:flex;align-items:center;justify-content:space-between;margin-bottom:8px}.lc-drp__nav{width:28px;height:28px;border:none;border-radius:var(--border-radius-sm);background:transparent;cursor:pointer;font-size:18px;color:var(--color-text-secondary);display:flex;align-items:center;justify-content:center}.lc-drp__nav:hover{background:var(--color-surface-hover)}.lc-drp__nav:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:0}.lc-drp__month{font-size:var(--typography-font-size-sm, .875rem);font-weight:600;color:var(--color-text-primary)}.lc-drp__weekdays{display:grid;grid-template-columns:repeat(7,1fr);gap:0;margin-bottom:4px}.lc-drp__weekday{text-align:center;font-size:.6875rem;font-weight:600;color:var(--color-text-tertiary);padding:4px}.lc-drp__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:0}.lc-drp__day{width:100%;aspect-ratio:1;display:flex;align-items:center;justify-content:center;border:none;background:transparent;cursor:pointer;font-size:.75rem;border-radius:var(--border-radius-sm);color:var(--color-text-primary);transition:all .1s}.lc-drp__day:hover:not(:disabled){background:var(--color-surface-hover)}.lc-drp__day:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px;z-index:1}.lc-drp__day--outside{color:var(--color-text-tertiary)}.lc-drp__day--disabled{color:var(--color-text-disabled);cursor:default}.lc-drp__day--today{font-weight:700;box-shadow:inset 0 -2px 0 var(--color-primary-500)}.lc-drp__day--start,.lc-drp__day--end{background:var(--color-primary-fill)!important;color:var(--color-on-primary)!important;font-weight:600}.lc-drp__day--in-range{background:var(--color-surface-selected);border-radius:0}.lc-drp__day--start{border-radius:var(--border-radius-sm) 0 0 var(--border-radius-sm)}.lc-drp__day--end{border-radius:0 var(--border-radius-sm) var(--border-radius-sm) 0}.lc-drp__footer{margin-top:8px;padding-top:8px;border-top:1px solid var(--color-divider)}.lc-drp__hint{font-size:.6875rem;color:var(--color-text-tertiary)}\n"]
369
371
  }]
370
372
  }],
@@ -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, ɵ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":"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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';\nimport { closestLang } from '@lifecorner/angular-ui-kit/internal/a11y';\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 /**\n * BCP 47 locale for the displayed dates, month title and weekday headers.\n * Also the open panel's `lang` when the host has no `[lang]` ancestor (3.30.2).\n * @default 'de-DE'\n */\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 /**\n * `lang` of the open panel (3.30.2, WCAG 3.1.2). The panel sits in the host\n * and inherits a `[lang]` ancestor through the DOM, so it gets one only\n * without any: then `locale`. `null` while closed.\n */\n protected readonly panelLang = computed(() =>\n this.isOpen() && closestLang(this.elRef.nativeElement) === null ? this.locale() || null : null\n );\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 [attr.lang]=\"panelLang()\"\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":";;;;;;AA0BA,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;CAMlC,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;CAOnE,YAAY,eAC7B,KAAK,OAAM,KAAM,YAAY,KAAK,MAAM,aAAa,MAAM,OAAO,KAAK,OAAM,KAAM,OAAO,MAC3F,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAEO,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;CArRW,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,UC1CH;EA+EA,QAAA,CAAA,85HAAA;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,85HAAA;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;GAiKtE,MAAA;GAAa,MAAA,CAAA,WAAW,CAAC,QAAQ,CAAC;;;GAUlC,MAAA;GAAa,MAAA,CAAA,kBAAkB,CAAC,QAAQ,CAAC"}