@coreui/angular 5.7.38 → 5.7.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from "@angular/core";
2
- import { ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, DOCUMENT, DestroyRef, Directive, ElementRef, HostBinding, HostListener, Injectable, Injector, Input, MAX_ANIMATION_TIMEOUT, NgModule, NgZone, PLATFORM_ID, Pipe, Renderer2, RendererFactory2, TemplateRef, ViewContainerRef, ViewEncapsulation, afterEveryRender, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChild, contentChildren, effect, forwardRef, inject, input, linkedSignal, model, numberAttribute, output, runInInjectionContext, signal, untracked, viewChild } from "@angular/core";
2
+ import { ApplicationRef, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChildren, DOCUMENT, DestroyRef, Directive, ElementRef, HostAttributeToken, HostBinding, HostListener, Injectable, Injector, Input, MAX_ANIMATION_TIMEOUT, NgModule, NgZone, PLATFORM_ID, Pipe, Renderer2, RendererFactory2, TemplateRef, ViewContainerRef, ViewEncapsulation, afterEveryRender, afterNextRender, afterRenderEffect, booleanAttribute, computed, contentChild, contentChildren, effect, forwardRef, inject, input, linkedSignal, model, numberAttribute, output, runInInjectionContext, signal, untracked, viewChild } from "@angular/core";
3
3
  import { DOCUMENT as DOCUMENT$1, NgTemplateOutlet, isPlatformBrowser, isPlatformServer } from "@angular/common";
4
4
  import { BehaviorSubject, EMPTY, Subject, fromEvent, merge, skipWhile, take, takeWhile } from "rxjs";
5
5
  import * as i1$1 from "@angular/router";
@@ -8051,6 +8051,17 @@ const isEditableTarget$1 = (target) => {
8051
8051
  };
8052
8052
  const clicksOnEnter = (element) => element instanceof HTMLButtonElement || element instanceof HTMLInputElement && /^(button|image|reset|submit)$/.test(element.type) || element instanceof HTMLAnchorElement && element.hasAttribute("href") || element.tagName === "SUMMARY";
8053
8053
  const clicksOnSpace = (element) => element instanceof HTMLButtonElement || element instanceof HTMLInputElement && /^(button|checkbox|image|radio|reset|submit)$/.test(element.type) || element.tagName === "SUMMARY";
8054
+ const restoreFocus = (overlay, candidates, focus = (target) => target.focus({ preventScroll: true })) => {
8055
+ const document = overlay.ownerDocument;
8056
+ const held = overlay.getRootNode().activeElement;
8057
+ const active = document.activeElement;
8058
+ if (!(held && overlay.contains(held)) && active && active !== document.body) return false;
8059
+ for (const target of candidates) if (target?.isConnected && !overlay.contains(target)) {
8060
+ focus(target);
8061
+ if (target.getRootNode().activeElement === target) return true;
8062
+ }
8063
+ return false;
8064
+ };
8054
8065
  var DropdownMenuDirective = class DropdownMenuDirective {
8055
8066
  #destroyRef = inject(DestroyRef);
8056
8067
  #injector = inject(Injector);
@@ -8232,7 +8243,9 @@ const alignmentClasses = (alignment) => {
8232
8243
  };
8233
8244
  const FOCUSABLE_SELECTOR = "a[href], button, input, select, textarea, [tabindex]";
8234
8245
  const FORM_TAG = /^(form|input|option|select|textarea)$/;
8246
+ const TEXT_INPUT_TYPE = /^(email|number|password|search|tel|text|url)$/;
8235
8247
  var DropdownToken = class {};
8248
+ var DropdownFocusReturn = class {};
8236
8249
  var DropdownToggleDirective = class DropdownToggleDirective {
8237
8250
  elementRef = inject(ElementRef);
8238
8251
  #renderer = inject(Renderer2);
@@ -8271,6 +8284,10 @@ var DropdownToggleDirective = class DropdownToggleDirective {
8271
8284
  }
8272
8285
  onKeyDown($event) {
8273
8286
  if (this.disabled() || isReplayedEvent($event) || isEditableTarget$1($event.target)) return;
8287
+ if ($event.repeat && $event.key === "Enter") {
8288
+ $event.preventDefault();
8289
+ return;
8290
+ }
8274
8291
  const element = this.elementRef.nativeElement;
8275
8292
  if ($event.target === element && element.tagName === "A" && ($event.key === " " || $event.key === "Enter" && !clicksOnEnter(element))) {
8276
8293
  $event.preventDefault();
@@ -8421,6 +8438,10 @@ var DropdownComponent = class DropdownComponent {
8421
8438
  #destroyRef = inject(DestroyRef);
8422
8439
  #document = inject(DOCUMENT);
8423
8440
  #elementRef = inject(ElementRef);
8441
+ #focusReturn = inject(DropdownFocusReturn, {
8442
+ host: true,
8443
+ optional: true
8444
+ });
8424
8445
  #injector = inject(Injector);
8425
8446
  #renderer = inject(Renderer2);
8426
8447
  #rtlService = inject(RtlService);
@@ -8488,10 +8509,12 @@ var DropdownComponent = class DropdownComponent {
8488
8509
  #visibleEffect = effect(() => {
8489
8510
  const visible = this.visible();
8490
8511
  untracked(() => {
8512
+ const closed = this.activeTrap && !visible;
8491
8513
  this.activeTrap = visible;
8492
8514
  visible ? this.createPopperInstance() : this.destroyPopperInstance();
8493
8515
  this.setVisibleState(visible);
8494
8516
  this.visibleChange?.emit(visible);
8517
+ if (closed) afterNextRender(() => this.#returnFocus(false), { injector: this.#injector });
8495
8518
  });
8496
8519
  }, ...ngDevMode ? [{ debugName: "#visibleEffect" }] : /* istanbul ignore next */ []);
8497
8520
  visibleChange = output();
@@ -8506,6 +8529,7 @@ var DropdownComponent = class DropdownComponent {
8506
8529
  activeTrap = false;
8507
8530
  popperInstance;
8508
8531
  listeners = [];
8532
+ #menuInteraction;
8509
8533
  hostClasses = computed(() => {
8510
8534
  const direction = this.direction();
8511
8535
  const variant = this.variant();
@@ -8572,6 +8596,15 @@ var DropdownComponent = class DropdownComponent {
8572
8596
  this.#changeDetectorRef.markForCheck();
8573
8597
  }
8574
8598
  setListeners() {
8599
+ this.#menuInteraction = void 0;
8600
+ const menu = this._menuElementRef()?.nativeElement;
8601
+ if (menu) this.#ngZone.runOutsideAngular(() => {
8602
+ for (const type of [
8603
+ "focusin",
8604
+ "keydown",
8605
+ "pointerdown"
8606
+ ]) this.listeners.push(this.#renderer.listen(menu, type, this.#trackMenuInteraction, { capture: true }));
8607
+ });
8575
8608
  this.listeners.push(this.#renderer.listen(this.#document, "click", (event) => {
8576
8609
  const part = this.#eventPart(event);
8577
8610
  if (part === "toggler" || part === "menu" && this.#isFormInteraction(event)) return;
@@ -8588,9 +8621,19 @@ var DropdownComponent = class DropdownComponent {
8588
8621
  #onEscape = (event) => {
8589
8622
  if (event.key !== "Escape" || event.defaultPrevented || this.autoClose() === false) return;
8590
8623
  event.preventDefault();
8591
- const focusInMenu = this._menuElementRef()?.nativeElement.contains(event.target);
8592
8624
  this.setVisibleState(false);
8593
- if (focusInMenu) this.#focusToggler();
8625
+ this.#returnFocus(true);
8626
+ };
8627
+ #trackMenuInteraction = (event) => {
8628
+ switch (event.type) {
8629
+ case "pointerdown":
8630
+ this.#menuInteraction = event.pointerType || "pointer";
8631
+ break;
8632
+ case "keydown":
8633
+ this.#menuInteraction = "keyboard";
8634
+ break;
8635
+ default: this.#menuInteraction ??= "focus";
8636
+ }
8594
8637
  };
8595
8638
  #directionPlacement() {
8596
8639
  const rtl = this.#rtlService.isRTL(this.#elementRef.nativeElement);
@@ -8618,16 +8661,24 @@ var DropdownComponent = class DropdownComponent {
8618
8661
  const path = event.composedPath();
8619
8662
  return path.slice(0, path.indexOf(this._menuElementRef()?.nativeElement) + 1).some((node) => node instanceof Element && FORM_TAG.test(node.localName));
8620
8663
  }
8621
- #focusToggler() {
8664
+ #returnFocus(escape) {
8665
+ const menu = this._menuElementRef()?.nativeElement;
8666
+ if (!menu || !this.#menuInteraction || !menu.ownerDocument.hasFocus()) return;
8667
+ restoreFocus(menu, this.#focusTargets(escape), (target) => this.#injector.get(FocusMonitor).focusVia(target, "program", { preventScroll: !escape }));
8668
+ }
8669
+ #focusTargets(escape) {
8670
+ const targets = this.#focusReturn?.focusReturnTargets() ?? this.#togglerTargets(escape);
8671
+ return this.#menuInteraction === "touch" || this.#menuInteraction === "pen" ? targets.filter((target) => !target || !this.#opensKeyboard(target)) : targets;
8672
+ }
8673
+ #togglerTargets(escape) {
8622
8674
  const toggler = this.#togglerElement();
8623
- if (!toggler) return;
8624
- const root = toggler.getRootNode();
8625
- const candidates = [toggler, ...toggler.querySelectorAll(FOCUSABLE_SELECTOR)].filter((candidate) => candidate === toggler || candidate.tabIndex >= 0 && !candidate.closest("[aria-hidden=\"true\"]"));
8626
- const focusMonitor = this.#injector.get(FocusMonitor);
8627
- for (const candidate of candidates) {
8628
- focusMonitor.focusVia(candidate, "program");
8629
- if (root.activeElement === candidate) return;
8630
- }
8675
+ if (!toggler || !escape) return toggler ? [toggler] : [];
8676
+ return [toggler, ...toggler.querySelectorAll(FOCUSABLE_SELECTOR)].filter((candidate) => candidate === toggler || candidate.tabIndex >= 0 && !candidate.closest("[aria-hidden=\"true\"]"));
8677
+ }
8678
+ #opensKeyboard(target) {
8679
+ if (target instanceof HTMLInputElement) return TEXT_INPUT_TYPE.test(target.type) && !target.readOnly;
8680
+ if (target instanceof HTMLTextAreaElement) return !target.readOnly;
8681
+ return !(target instanceof HTMLSelectElement) && isEditableTarget$1(target);
8631
8682
  }
8632
8683
  clearListeners() {
8633
8684
  this.listeners.forEach((unListen) => {
@@ -9642,6 +9693,31 @@ i0.ɵɵngDeclareClassMetadata({
9642
9693
  }]
9643
9694
  }
9644
9695
  });
9696
+ const TYPES_WITHOUT_ARIA_INVALID = [
9697
+ "button",
9698
+ "color",
9699
+ "hidden",
9700
+ "image",
9701
+ "reset",
9702
+ "submit"
9703
+ ];
9704
+ const bindAriaInvalid = (valid, type) => {
9705
+ const host = inject(ElementRef).nativeElement;
9706
+ const renderer = inject(Renderer2);
9707
+ const templateValue = inject(new HostAttributeToken("aria-invalid"), { optional: true });
9708
+ let invalidated = false;
9709
+ return effect(() => {
9710
+ if (valid() === false && !TYPES_WITHOUT_ARIA_INVALID.includes(String(type?.() ?? "").toLowerCase())) {
9711
+ const current = host.getAttribute("aria-invalid");
9712
+ if (!current || current.toLowerCase() === "false") renderer.setAttribute(host, "aria-invalid", "true");
9713
+ invalidated = true;
9714
+ } else if (invalidated) {
9715
+ if (templateValue === null) renderer.removeAttribute(host, "aria-invalid");
9716
+ else renderer.setAttribute(host, "aria-invalid", templateValue);
9717
+ invalidated = false;
9718
+ }
9719
+ });
9720
+ };
9645
9721
  var FormControlDirective = class FormControlDirective {
9646
9722
  #hostElement = inject(ElementRef);
9647
9723
  sizing = input(...ngDevMode ? [void 0, { debugName: "sizing" }] : /* istanbul ignore next */ []);
@@ -9651,6 +9727,7 @@ var FormControlDirective = class FormControlDirective {
9651
9727
  ...ngDevMode ? { debugName: "plaintext" } : /* istanbul ignore next */ {},
9652
9728
  transform: booleanAttribute
9653
9729
  });
9730
+ #ariaInvalidEffect = bindAriaInvalid(this.valid, this.type);
9654
9731
  hostClasses = computed(() => {
9655
9732
  const type = this.type();
9656
9733
  const isRange = type === "range";
@@ -9797,6 +9874,7 @@ var FormCheckInputDirective = class FormCheckInputDirective {
9797
9874
  return this.#indeterminate();
9798
9875
  }
9799
9876
  valid = input(...ngDevMode ? [void 0, { debugName: "valid" }] : /* istanbul ignore next */ []);
9877
+ #ariaInvalidEffect = bindAriaInvalid(this.valid);
9800
9878
  hostClasses = computed(() => {
9801
9879
  const valid = this.valid();
9802
9880
  return {
@@ -10116,6 +10194,7 @@ i0.ɵɵngDeclareClassMetadata({
10116
10194
  var FormSelectDirective = class FormSelectDirective {
10117
10195
  sizing = input(...ngDevMode ? [void 0, { debugName: "sizing" }] : /* istanbul ignore next */ []);
10118
10196
  valid = input(...ngDevMode ? [void 0, { debugName: "valid" }] : /* istanbul ignore next */ []);
10197
+ #ariaInvalidEffect = bindAriaInvalid(this.valid);
10119
10198
  hostClasses = computed(() => {
10120
10199
  const sizing = this.sizing();
10121
10200
  const valid = this.valid();
@@ -13826,16 +13905,6 @@ i0.ɵɵngDeclareClassMetadata({
13826
13905
  }]
13827
13906
  }]
13828
13907
  });
13829
- const restoreFocus = (overlay, candidates) => {
13830
- const document = overlay.ownerDocument;
13831
- const active = document.activeElement;
13832
- if (active && active !== document.body && !overlay.contains(active)) return false;
13833
- for (const target of candidates) if (target?.isConnected && !overlay.contains(target)) {
13834
- target.focus({ preventScroll: true });
13835
- if (document.activeElement === target) return true;
13836
- }
13837
- return false;
13838
- };
13839
13908
  var ModalComponent = class ModalComponent {
13840
13909
  #document = inject(DOCUMENT);
13841
13910
  #renderer = inject(Renderer2);
@@ -13925,7 +13994,7 @@ var ModalComponent = class ModalComponent {
13925
13994
  untracked(() => {
13926
13995
  if (visible && afterViewInit) {
13927
13996
  this.#focusBeforeShow = this.#document.activeElement;
13928
- setTimeout(() => {
13997
+ if (isPlatformBrowser(this.#platformId)) setTimeout(() => {
13929
13998
  if (!this.focusTrap()?.focusTrap.focusInitialElement()) this.#hostElement.nativeElement.focus();
13930
13999
  });
13931
14000
  } else this.#restoreFocus();