ng-primitives 0.44.0 → 0.45.1

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.
Files changed (45) hide show
  1. package/combobox/combobox/combobox-state.d.ts +3 -2
  2. package/combobox/combobox/combobox.d.ts +9 -3
  3. package/combobox/combobox-button/combobox-button.d.ts +3 -2
  4. package/combobox/combobox-dropdown/combobox-dropdown.d.ts +52 -2
  5. package/combobox/combobox-input/combobox-input.d.ts +3 -2
  6. package/combobox/combobox-option/combobox-option.d.ts +3 -2
  7. package/combobox/combobox-portal/combobox-portal.d.ts +10 -21
  8. package/example-theme/index.css +1 -0
  9. package/fesm2022/ng-primitives-combobox.mjs +66 -87
  10. package/fesm2022/ng-primitives-combobox.mjs.map +1 -1
  11. package/fesm2022/ng-primitives-focus-trap.mjs +9 -1
  12. package/fesm2022/ng-primitives-focus-trap.mjs.map +1 -1
  13. package/fesm2022/ng-primitives-listbox.mjs +1 -1
  14. package/fesm2022/ng-primitives-listbox.mjs.map +1 -1
  15. package/fesm2022/ng-primitives-menu.mjs +382 -63
  16. package/fesm2022/ng-primitives-menu.mjs.map +1 -1
  17. package/fesm2022/ng-primitives-popover.mjs +66 -331
  18. package/fesm2022/ng-primitives-popover.mjs.map +1 -1
  19. package/fesm2022/ng-primitives-portal.mjs +360 -2
  20. package/fesm2022/ng-primitives-portal.mjs.map +1 -1
  21. package/fesm2022/ng-primitives-tooltip.mjs +56 -176
  22. package/fesm2022/ng-primitives-tooltip.mjs.map +1 -1
  23. package/focus-trap/focus-trap/focus-trap-state.d.ts +1 -0
  24. package/focus-trap/focus-trap/focus-trap.d.ts +5 -0
  25. package/menu/config/menu-config.d.ts +42 -0
  26. package/menu/index.d.ts +5 -1
  27. package/menu/menu/menu.d.ts +6 -2
  28. package/menu/menu-trigger/menu-trigger-state.d.ts +38 -0
  29. package/menu/menu-trigger/menu-trigger.d.ts +91 -13
  30. package/menu/submenu-trigger/submenu-trigger-state.d.ts +58 -0
  31. package/menu/submenu-trigger/submenu-trigger.d.ts +66 -10
  32. package/package.json +12 -12
  33. package/popover/index.d.ts +1 -2
  34. package/popover/popover/popover.d.ts +2 -43
  35. package/popover/popover-trigger/popover-trigger.d.ts +16 -106
  36. package/portal/index.d.ts +2 -0
  37. package/portal/overlay-token.d.ts +12 -0
  38. package/portal/overlay.d.ts +172 -0
  39. package/schematics/ng-generate/templates/combobox/combobox.__fileSuffix@dasherize__.ts.template +31 -0
  40. package/tooltip/index.d.ts +1 -1
  41. package/tooltip/tooltip/tooltip.d.ts +3 -25
  42. package/tooltip/tooltip-trigger/tooltip-trigger.d.ts +16 -63
  43. package/popover/popover/popover-token.d.ts +0 -10
  44. package/popover/utils/transform-origin.d.ts +0 -2
  45. package/tooltip/tooltip/tooltip-token.d.ts +0 -10
@@ -19,12 +19,13 @@ export declare const injectComboboxState: <U = {
19
19
  readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, import("@angular/cdk/coercion").BooleanInput>;
20
20
  readonly openChange: import("@angular/core").OutputEmitterRef<boolean>;
21
21
  readonly compareWith: import("@angular/core").InputSignal<(a: any | undefined, b: any | undefined) => boolean>;
22
- readonly dropdownPosition: import("@angular/core").InputSignal<"top" | "bottom" | "auto">;
22
+ readonly placement: import("@angular/core").InputSignal<import("@floating-ui/dom").Placement>;
23
23
  readonly input: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxInput | undefined>;
24
24
  readonly button: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxButton | undefined>;
25
25
  readonly portal: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxPortal | undefined>;
26
26
  readonly dropdown: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxDropdown | undefined>;
27
27
  readonly options: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxOption[]>;
28
+ readonly overlay: import("@angular/core").Signal<import("ng-primitives/portal").NgpOverlay<void> | null | undefined>;
28
29
  readonly open: import("@angular/core").Signal<boolean>;
29
30
  readonly activeDescendantManager: {
30
31
  activeDescendant: import("@angular/core").Signal<string | undefined>;
@@ -37,7 +38,7 @@ export declare const injectComboboxState: <U = {
37
38
  reset: () => void;
38
39
  };
39
40
  readonly state: import("ng-primitives/state").CreatedState<NgpCombobox>;
40
- openDropdown: () => void;
41
+ openDropdown: () => Promise<void>;
41
42
  closeDropdown: () => void;
42
43
  toggleDropdown: () => void;
43
44
  selectOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
@@ -1,5 +1,6 @@
1
1
  import { BooleanInput } from '@angular/cdk/coercion';
2
2
  import { Injector } from '@angular/core';
3
+ import { Placement } from '@floating-ui/dom';
3
4
  import type { NgpComboboxButton } from '../combobox-button/combobox-button';
4
5
  import type { NgpComboboxDropdown } from '../combobox-dropdown/combobox-dropdown';
5
6
  import type { NgpComboboxInput } from '../combobox-input/combobox-input';
@@ -36,7 +37,7 @@ export declare class NgpCombobox {
36
37
  /** The comparator function used to compare options. */
37
38
  readonly compareWith: import("@angular/core").InputSignal<(a: T | undefined, b: T | undefined) => boolean>;
38
39
  /** The position of the dropdown. */
39
- readonly dropdownPosition: import("@angular/core").InputSignal<"top" | "bottom" | "auto">;
40
+ readonly placement: import("@angular/core").InputSignal<Placement>;
40
41
  /**
41
42
  * Store the combobox input
42
43
  * @internal
@@ -62,6 +63,11 @@ export declare class NgpCombobox {
62
63
  * @internal
63
64
  */
64
65
  readonly options: import("@angular/core").WritableSignal<NgpComboboxOption[]>;
66
+ /**
67
+ * Access the overlay
68
+ * @internal
69
+ */
70
+ readonly overlay: import("@angular/core").Signal<import("ng-primitives/portal").NgpOverlay<void> | null | undefined>;
65
71
  /**
66
72
  * The open state of the combobox.
67
73
  * @internal
@@ -88,7 +94,7 @@ export declare class NgpCombobox {
88
94
  * Open the dropdown.
89
95
  * @internal
90
96
  */
91
- openDropdown(): void;
97
+ openDropdown(): Promise<void>;
92
98
  /**
93
99
  * Close the dropdown.
94
100
  * @internal
@@ -171,6 +177,6 @@ export declare class NgpCombobox {
171
177
  */
172
178
  unregisterOption(option: NgpComboboxOption): void;
173
179
  static ɵfac: i0.ɵɵFactoryDeclaration<NgpCombobox, never>;
174
- static ɵdir: i0.ɵɵDirectiveDeclaration<NgpCombobox, "[ngpCombobox]", ["ngpCombobox"], { "value": { "alias": "ngpComboboxValue"; "required": false; "isSignal": true; }; "multiple": { "alias": "ngpComboboxMultiple"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpComboboxDisabled"; "required": false; "isSignal": true; }; "compareWith": { "alias": "ngpComboboxCompareWith"; "required": false; "isSignal": true; }; "dropdownPosition": { "alias": "ngpComboboxDropdownPosition"; "required": false; "isSignal": true; }; }, { "valueChange": "ngpComboboxValueChange"; "openChange": "ngpComboboxOpenChange"; }, never, never, true, never>;
180
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NgpCombobox, "[ngpCombobox]", ["ngpCombobox"], { "value": { "alias": "ngpComboboxValue"; "required": false; "isSignal": true; }; "multiple": { "alias": "ngpComboboxMultiple"; "required": false; "isSignal": true; }; "disabled": { "alias": "ngpComboboxDisabled"; "required": false; "isSignal": true; }; "compareWith": { "alias": "ngpComboboxCompareWith"; "required": false; "isSignal": true; }; "placement": { "alias": "ngpComboboxDropdownPlacement"; "required": false; "isSignal": true; }; }, { "valueChange": "ngpComboboxValueChange"; "openChange": "ngpComboboxOpenChange"; }, never, never, true, never>;
175
181
  }
176
182
  export {};
@@ -10,12 +10,13 @@ export declare class NgpComboboxButton {
10
10
  readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, import("@angular/cdk/coercion").BooleanInput>;
11
11
  readonly openChange: import("@angular/core").OutputEmitterRef<boolean>;
12
12
  readonly compareWith: import("@angular/core").InputSignal<(a: any | undefined, b: any | undefined) => boolean>;
13
- readonly dropdownPosition: import("@angular/core").InputSignal<"top" | "bottom" | "auto">;
13
+ readonly placement: import("@angular/core").InputSignal<import("@floating-ui/dom").Placement>;
14
14
  readonly input: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxInput | undefined>;
15
15
  readonly button: import("@angular/core").WritableSignal<NgpComboboxButton | undefined>;
16
16
  readonly portal: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxPortal | undefined>;
17
17
  readonly dropdown: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxDropdown | undefined>;
18
18
  readonly options: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxOption[]>;
19
+ readonly overlay: import("@angular/core").Signal<import("ng-primitives/portal").NgpOverlay<void> | null | undefined>;
19
20
  readonly open: import("@angular/core").Signal<boolean>;
20
21
  readonly activeDescendantManager: {
21
22
  activeDescendant: import("@angular/core").Signal<string | undefined>;
@@ -28,7 +29,7 @@ export declare class NgpComboboxButton {
28
29
  reset: () => void;
29
30
  };
30
31
  readonly state: import("ng-primitives/state").CreatedState<import("ng-primitives/combobox").NgpCombobox>;
31
- openDropdown: () => void;
32
+ openDropdown: () => Promise<void>;
32
33
  closeDropdown: () => void;
33
34
  toggleDropdown: () => void;
34
35
  selectOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
@@ -1,7 +1,57 @@
1
1
  import * as i0 from "@angular/core";
2
+ import * as i1 from "ng-primitives/internal";
2
3
  export declare class NgpComboboxDropdown {
3
4
  /** Access the combobox state. */
4
- private readonly state;
5
+ protected readonly state: import("@angular/core").Signal<import("ng-primitives/state").State<{
6
+ readonly elementRef: import("@angular/core").ElementRef<HTMLElement>;
7
+ readonly injector: import("@angular/core").Injector;
8
+ readonly value: import("@angular/core").InputSignal<any>;
9
+ readonly valueChange: import("@angular/core").OutputEmitterRef<any>;
10
+ readonly multiple: import("@angular/core").InputSignalWithTransform<boolean, import("@angular/cdk/coercion").BooleanInput>;
11
+ readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, import("@angular/cdk/coercion").BooleanInput>;
12
+ readonly openChange: import("@angular/core").OutputEmitterRef<boolean>;
13
+ readonly compareWith: import("@angular/core").InputSignal<(a: any | undefined, b: any | undefined) => boolean>;
14
+ readonly placement: import("@angular/core").InputSignal<import("@floating-ui/dom").Placement>;
15
+ readonly input: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxInput | undefined>;
16
+ readonly button: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxButton | undefined>;
17
+ readonly portal: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxPortal | undefined>;
18
+ readonly dropdown: import("@angular/core").WritableSignal<NgpComboboxDropdown | undefined>;
19
+ readonly options: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxOption[]>;
20
+ readonly overlay: import("@angular/core").Signal<import("ng-primitives/portal").NgpOverlay<void> | null | undefined>;
21
+ readonly open: import("@angular/core").Signal<boolean>;
22
+ readonly activeDescendantManager: {
23
+ activeDescendant: import("@angular/core").Signal<string | undefined>;
24
+ activeItem: import("@angular/core").Signal<import("ng-primitives/combobox").NgpComboboxOption | undefined>;
25
+ activate: (item: import("ng-primitives/combobox").NgpComboboxOption | undefined) => void;
26
+ first: () => void;
27
+ last: () => void;
28
+ next: () => void;
29
+ previous: () => void;
30
+ reset: () => void;
31
+ };
32
+ readonly state: import("ng-primitives/state").CreatedState<import("ng-primitives/combobox").NgpCombobox>;
33
+ openDropdown: () => Promise<void>;
34
+ closeDropdown: () => void;
35
+ toggleDropdown: () => void;
36
+ selectOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
37
+ deselectOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
38
+ toggleOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
39
+ isOptionSelected: (option: import("ng-primitives/combobox").NgpComboboxOption) => boolean;
40
+ activateNextOption: () => void;
41
+ activatePreviousOption: () => void;
42
+ registerPortal: (portal: import("ng-primitives/combobox").NgpComboboxPortal) => void;
43
+ registerInput: (input: import("ng-primitives/combobox").NgpComboboxInput) => void;
44
+ registerButton: (button: import("ng-primitives/combobox").NgpComboboxButton) => void;
45
+ registerDropdown: (dropdown: NgpComboboxDropdown) => void;
46
+ registerOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
47
+ unregisterOption: (option: import("ng-primitives/combobox").NgpComboboxOption) => void;
48
+ }>>;
49
+ /** The dimensions of the combobox. */
50
+ protected readonly comboboxDimensions: import("@angular/core").Signal<import("ng-primitives/resize").Dimensions>;
51
+ /** The dimensions of the combobox. */
52
+ protected readonly inputDimensions: import("@angular/core").Signal<import("ng-primitives/resize").Dimensions>;
53
+ /** Store the combobox button dimensions. */
54
+ protected readonly buttonDimensions: import("@angular/core").Signal<import("ng-primitives/resize").Dimensions>;
5
55
  /**
6
56
  * Access the element reference.
7
57
  * @internal
@@ -11,5 +61,5 @@ export declare class NgpComboboxDropdown {
11
61
  readonly id: import("@angular/core").InputSignal<string>;
12
62
  constructor();
13
63
  static ɵfac: i0.ɵɵFactoryDeclaration<NgpComboboxDropdown, never>;
14
- static ɵdir: i0.ɵɵDirectiveDeclaration<NgpComboboxDropdown, "[ngpComboboxDropdown]", ["ngpComboboxDropdown"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
64
+ static ɵdir: i0.ɵɵDirectiveDeclaration<NgpComboboxDropdown, "[ngpComboboxDropdown]", ["ngpComboboxDropdown"], { "id": { "alias": "id"; "required": false; "isSignal": true; }; }, {}, never, never, true, [{ directive: typeof i1.NgpExitAnimation; inputs: {}; outputs: {}; }]>;
15
65
  }
@@ -11,12 +11,13 @@ export declare class NgpComboboxInput {
11
11
  readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, import("@angular/cdk/coercion").BooleanInput>;
12
12
  readonly openChange: import("@angular/core").OutputEmitterRef<boolean>;
13
13
  readonly compareWith: import("@angular/core").InputSignal<(a: any | undefined, b: any | undefined) => boolean>;
14
- readonly dropdownPosition: import("@angular/core").InputSignal<"top" | "bottom" | "auto">;
14
+ readonly placement: import("@angular/core").InputSignal<import("@floating-ui/dom").Placement>;
15
15
  readonly input: import("@angular/core").WritableSignal<NgpComboboxInput | undefined>;
16
16
  readonly button: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxButton | undefined>;
17
17
  readonly portal: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxPortal | undefined>;
18
18
  readonly dropdown: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxDropdown | undefined>;
19
19
  readonly options: import("@angular/core").WritableSignal<NgpComboboxOption[]>;
20
+ readonly overlay: import("@angular/core").Signal<import("ng-primitives/portal").NgpOverlay<void> | null | undefined>;
20
21
  readonly open: import("@angular/core").Signal<boolean>;
21
22
  readonly activeDescendantManager: {
22
23
  activeDescendant: import("@angular/core").Signal<string | undefined>;
@@ -29,7 +30,7 @@ export declare class NgpComboboxInput {
29
30
  reset: () => void;
30
31
  };
31
32
  readonly state: import("ng-primitives/state").CreatedState<import("ng-primitives/combobox").NgpCombobox>;
32
- openDropdown: () => void;
33
+ openDropdown: () => Promise<void>;
33
34
  closeDropdown: () => void;
34
35
  toggleDropdown: () => void;
35
36
  selectOption: (option: NgpComboboxOption) => void;
@@ -13,12 +13,13 @@ export declare class NgpComboboxOption implements OnInit, OnDestroy, NgpActivata
13
13
  readonly disabled: import("@angular/core").InputSignalWithTransform<boolean, BooleanInput>;
14
14
  readonly openChange: import("@angular/core").OutputEmitterRef<boolean>;
15
15
  readonly compareWith: import("@angular/core").InputSignal<(a: any | undefined, b: any | undefined) => boolean>;
16
- readonly dropdownPosition: import("@angular/core").InputSignal<"top" | "bottom" | "auto">;
16
+ readonly placement: import("@angular/core").InputSignal<import("@floating-ui/dom").Placement>;
17
17
  readonly input: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxInput | undefined>;
18
18
  readonly button: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxButton | undefined>;
19
19
  readonly portal: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxPortal | undefined>;
20
20
  readonly dropdown: import("@angular/core").WritableSignal<import("ng-primitives/combobox").NgpComboboxDropdown | undefined>;
21
21
  readonly options: import("@angular/core").WritableSignal<NgpComboboxOption[]>;
22
+ readonly overlay: import("@angular/core").Signal<import("ng-primitives/portal").NgpOverlay<void> | null | undefined>;
22
23
  readonly open: import("@angular/core").Signal<boolean>;
23
24
  readonly activeDescendantManager: {
24
25
  activeDescendant: import("@angular/core").Signal<string | undefined>;
@@ -31,7 +32,7 @@ export declare class NgpComboboxOption implements OnInit, OnDestroy, NgpActivata
31
32
  reset: () => void;
32
33
  };
33
34
  readonly state: import("ng-primitives/state").CreatedState<import("ng-primitives/combobox").NgpCombobox>;
34
- openDropdown: () => void;
35
+ openDropdown: () => Promise<void>;
35
36
  closeDropdown: () => void;
36
37
  toggleDropdown: () => void;
37
38
  selectOption: (option: NgpComboboxOption) => void;
@@ -1,35 +1,20 @@
1
1
  import { OnDestroy } from '@angular/core';
2
- import { NgpPortal } from 'ng-primitives/portal';
2
+ import { NgpOverlay } from 'ng-primitives/portal';
3
3
  import * as i0 from "@angular/core";
4
4
  export declare class NgpComboboxPortal implements OnDestroy {
5
5
  /** Access the combobox state. */
6
6
  private readonly state;
7
- /** Access the template reference. */
8
- private readonly templateRef;
9
7
  /** Access the view container reference. */
10
8
  private readonly viewContainerRef;
9
+ /** Access the template reference. */
10
+ private readonly templateRef;
11
11
  /** Access the injector. */
12
12
  private readonly injector;
13
- /** Access the document. */
14
- private readonly document;
15
13
  /**
16
- * Store the embedded view reference.
14
+ * The overlay that manages the popover
17
15
  * @internal
18
16
  */
19
- readonly viewRef: import("@angular/core").WritableSignal<NgpPortal | null>;
20
- /** Store the dispose function. */
21
- private dispose;
22
- /** The position of the dropdown. */
23
- readonly position: import("@angular/core").WritableSignal<{
24
- x: number;
25
- y: number;
26
- }>;
27
- /** The dimensions of the combobox. */
28
- private readonly comboboxDimensions;
29
- /** The dimensions of the combobox. */
30
- private readonly inputDimensions;
31
- /** Store the combobox button dimensions. */
32
- private readonly buttonDimensions;
17
+ readonly overlay: import("@angular/core").WritableSignal<NgpOverlay<void> | null>;
33
18
  constructor();
34
19
  /** Cleanup the portal. */
35
20
  ngOnDestroy(): void;
@@ -37,12 +22,16 @@ export declare class NgpComboboxPortal implements OnDestroy {
37
22
  * Attach the portal.
38
23
  * @internal
39
24
  */
40
- attach(): void;
25
+ show(): Promise<void>;
41
26
  /**
42
27
  * Detach the portal.
43
28
  * @internal
44
29
  */
45
30
  detach(): Promise<void>;
31
+ /**
32
+ * Create the overlay that will contain the dropdown
33
+ */
34
+ private createOverlay;
46
35
  static ɵfac: i0.ɵɵFactoryDeclaration<NgpComboboxPortal, never>;
47
36
  static ɵdir: i0.ɵɵDirectiveDeclaration<NgpComboboxPortal, "[ngpComboboxPortal]", ["ngpComboboxPortal"], {}, {}, never, never, true, never>;
48
37
  }
@@ -42,6 +42,7 @@
42
42
  --ngp-text-red: #ef4444;
43
43
 
44
44
  --ngp-shadow: 0 1px 2px 0 rgba(0 0 0 0.05);
45
+ --ngp-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1);
45
46
  --ngp-shadow-border: inset 0 0 0 1px rgba(0, 0, 0, 0.1);
46
47
 
47
48
  --ngp-focus-ring: rgb(59 130 246);
@@ -1,12 +1,11 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, Directive, computed, HostListener, booleanAttribute, inject, TemplateRef, ViewContainerRef, Injector, signal, effect, output, afterNextRender } from '@angular/core';
3
- import { injectElementRef, setupInteractions, explicitEffect } from 'ng-primitives/internal';
2
+ import { input, Directive, computed, HostListener, booleanAttribute, inject, ViewContainerRef, TemplateRef, Injector, signal, output, afterNextRender } from '@angular/core';
3
+ import * as i1 from 'ng-primitives/internal';
4
+ import { injectElementRef, NgpExitAnimation, setupInteractions, explicitEffect, provideExitAnimationManager } from 'ng-primitives/internal';
5
+ import { observeResize } from 'ng-primitives/resize';
4
6
  import { uniqueId } from 'ng-primitives/utils';
5
7
  import { createStateToken, createStateProvider, createStateInjector, createState } from 'ng-primitives/state';
6
- import { DOCUMENT } from '@angular/common';
7
- import { flip, autoUpdate, computePosition } from '@floating-ui/dom';
8
- import { createPortal } from 'ng-primitives/portal';
9
- import { observeResize } from 'ng-primitives/resize';
8
+ import { createOverlay } from 'ng-primitives/portal';
10
9
  import { activeDescendantManager } from 'ng-primitives/a11y';
11
10
 
12
11
  /**
@@ -30,6 +29,12 @@ class NgpComboboxDropdown {
30
29
  constructor() {
31
30
  /** Access the combobox state. */
32
31
  this.state = injectComboboxState();
32
+ /** The dimensions of the combobox. */
33
+ this.comboboxDimensions = observeResize(() => this.state().elementRef.nativeElement);
34
+ /** The dimensions of the combobox. */
35
+ this.inputDimensions = observeResize(() => this.state().input()?.elementRef.nativeElement);
36
+ /** Store the combobox button dimensions. */
37
+ this.buttonDimensions = observeResize(() => this.state().button()?.elementRef.nativeElement);
33
38
  /**
34
39
  * Access the element reference.
35
40
  * @internal
@@ -40,16 +45,23 @@ class NgpComboboxDropdown {
40
45
  this.state().registerDropdown(this);
41
46
  }
42
47
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpComboboxDropdown, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
43
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpComboboxDropdown, isStandalone: true, selector: "[ngpComboboxDropdown]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listbox" }, properties: { "id": "id()" } }, exportAs: ["ngpComboboxDropdown"], ngImport: i0 }); }
48
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpComboboxDropdown, isStandalone: true, selector: "[ngpComboboxDropdown]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "role": "listbox" }, properties: { "id": "id()", "style.left.px": "state().overlay()?.position()?.x", "style.top.px": "state().overlay()?.position()?.y", "style.--ngp-combobox-transform-origin": "state().overlay()?.transformOrigin()", "style.--ngp-combobox-width.px": "comboboxDimensions().width", "style.--ngp-combobox-input-width.px": "inputDimensions().width", "style.--ngp-combobox-button-width.px": "buttonDimensions().width" } }, exportAs: ["ngpComboboxDropdown"], hostDirectives: [{ directive: i1.NgpExitAnimation }], ngImport: i0 }); }
44
49
  }
45
50
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpComboboxDropdown, decorators: [{
46
51
  type: Directive,
47
52
  args: [{
48
53
  selector: '[ngpComboboxDropdown]',
49
54
  exportAs: 'ngpComboboxDropdown',
55
+ hostDirectives: [NgpExitAnimation],
50
56
  host: {
51
57
  role: 'listbox',
52
58
  '[id]': 'id()',
59
+ '[style.left.px]': 'state().overlay()?.position()?.x',
60
+ '[style.top.px]': 'state().overlay()?.position()?.y',
61
+ '[style.--ngp-combobox-transform-origin]': 'state().overlay()?.transformOrigin()',
62
+ '[style.--ngp-combobox-width.px]': 'comboboxDimensions().width',
63
+ '[style.--ngp-combobox-input-width.px]': 'inputDimensions().width',
64
+ '[style.--ngp-combobox-button-width.px]': 'buttonDimensions().width',
53
65
  },
54
66
  }]
55
67
  }], ctorParameters: () => [] });
@@ -327,101 +339,59 @@ class NgpComboboxPortal {
327
339
  constructor() {
328
340
  /** Access the combobox state. */
329
341
  this.state = injectComboboxState();
330
- /** Access the template reference. */
331
- this.templateRef = inject(TemplateRef);
332
342
  /** Access the view container reference. */
333
343
  this.viewContainerRef = inject(ViewContainerRef);
344
+ /** Access the template reference. */
345
+ this.templateRef = inject(TemplateRef);
334
346
  /** Access the injector. */
335
347
  this.injector = inject(Injector);
336
- /** Access the document. */
337
- this.document = inject(DOCUMENT);
338
348
  /**
339
- * Store the embedded view reference.
349
+ * The overlay that manages the popover
340
350
  * @internal
341
351
  */
342
- this.viewRef = signal(null);
343
- /** Store the dispose function. */
344
- this.dispose = null;
345
- /** The position of the dropdown. */
346
- this.position = signal({ x: 0, y: 0 });
347
- /** The dimensions of the combobox. */
348
- this.comboboxDimensions = observeResize(() => this.state().elementRef.nativeElement);
349
- /** The dimensions of the combobox. */
350
- this.inputDimensions = observeResize(() => this.state().input()?.elementRef.nativeElement);
351
- /** Store the combobox button dimensions. */
352
- this.buttonDimensions = observeResize(() => this.state().button()?.elementRef.nativeElement);
352
+ this.overlay = signal(null);
353
353
  this.state().registerPortal(this);
354
- effect(() => {
355
- const dropdownElement = this.viewRef()?.getElements()[0];
356
- if (!dropdownElement) {
357
- return;
358
- }
359
- const position = this.position();
360
- const comboboxWidth = this.comboboxDimensions().width;
361
- const inputWidth = this.inputDimensions().width;
362
- const buttonWidth = this.buttonDimensions().width;
363
- if (!dropdownElement) {
364
- return;
365
- }
366
- const styles = {
367
- position: 'absolute',
368
- left: `${position.x}px`,
369
- top: `${position.y}px`,
370
- '--ngp-combobox-width': `${comboboxWidth}px`,
371
- '--ngp-combobox-input-width': `${inputWidth}px`,
372
- '--ngp-combobox-button-width': `${buttonWidth}px`,
373
- };
374
- for (const [key, value] of Object.entries(styles)) {
375
- dropdownElement.style.setProperty(key, value);
376
- }
377
- });
378
354
  }
379
355
  /** Cleanup the portal. */
380
356
  ngOnDestroy() {
381
- this.detach();
382
- this.dispose?.();
357
+ this.overlay()?.destroy();
383
358
  }
384
359
  /**
385
360
  * Attach the portal.
386
361
  * @internal
387
362
  */
388
- attach() {
389
- const viewRef = createPortal(this.templateRef, this.viewContainerRef, this.injector);
390
- viewRef.attach(this.document.body);
391
- viewRef.detectChanges();
392
- this.viewRef.set(viewRef);
393
- const dropdownElement = this.viewRef()?.getElements()[0];
394
- if (!dropdownElement) {
395
- throw new Error('Dropdown element not found');
363
+ show() {
364
+ // Create the overlay if it doesn't exist yet
365
+ if (!this.overlay()) {
366
+ this.createOverlay();
396
367
  }
397
- let placement;
398
- const middleware = [];
399
- switch (this.state().dropdownPosition()) {
400
- case 'top':
401
- placement = 'top-start';
402
- break;
403
- case 'bottom':
404
- placement = 'bottom-start';
405
- break;
406
- case 'auto':
407
- placement = 'bottom-start';
408
- middleware.push(flip({ fallbackPlacements: ['top-start'] }));
409
- break;
410
- }
411
- this.dispose = autoUpdate(this.state().elementRef.nativeElement, dropdownElement, async () => {
412
- const position = await computePosition(this.state().elementRef.nativeElement, dropdownElement, { placement, middleware, strategy: 'absolute' });
413
- this.position.set({ x: position.x, y: position.y });
414
- });
368
+ // Show the overlay
369
+ return this.overlay().show();
415
370
  }
416
371
  /**
417
372
  * Detach the portal.
418
373
  * @internal
419
374
  */
420
375
  async detach() {
421
- await this.viewRef()?.detach();
422
- this.viewRef.set(null);
423
- this.dispose?.();
424
- this.dispose = null;
376
+ this.overlay()?.hide();
377
+ }
378
+ /**
379
+ * Create the overlay that will contain the dropdown
380
+ */
381
+ createOverlay() {
382
+ // Create config for the overlay
383
+ const config = {
384
+ content: this.templateRef,
385
+ viewContainerRef: this.viewContainerRef,
386
+ triggerElement: this.state().elementRef.nativeElement,
387
+ injector: this.injector,
388
+ placement: this.state().placement(),
389
+ closeOnOutsideClick: true,
390
+ closeOnEscape: true,
391
+ restoreFocus: false,
392
+ scrollBehaviour: 'reposition',
393
+ };
394
+ this.overlay.set(createOverlay(config));
425
395
  }
426
396
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpComboboxPortal, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
427
397
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpComboboxPortal, isStandalone: true, selector: "[ngpComboboxPortal]", exportAs: ["ngpComboboxPortal"], ngImport: i0 }); }
@@ -467,8 +437,8 @@ class NgpCombobox {
467
437
  alias: 'ngpComboboxCompareWith',
468
438
  });
469
439
  /** The position of the dropdown. */
470
- this.dropdownPosition = input('bottom', {
471
- alias: 'ngpComboboxDropdownPosition',
440
+ this.placement = input('bottom', {
441
+ alias: 'ngpComboboxDropdownPlacement',
472
442
  });
473
443
  /**
474
444
  * Store the combobox input
@@ -495,11 +465,16 @@ class NgpCombobox {
495
465
  * @internal
496
466
  */
497
467
  this.options = signal([]);
468
+ /**
469
+ * Access the overlay
470
+ * @internal
471
+ */
472
+ this.overlay = computed(() => this.portal()?.overlay());
498
473
  /**
499
474
  * The open state of the combobox.
500
475
  * @internal
501
476
  */
502
- this.open = computed(() => this.portal()?.viewRef() !== null);
477
+ this.open = computed(() => this.overlay()?.isOpen() ?? false);
503
478
  /**
504
479
  * The active key descendant manager.
505
480
  * @internal
@@ -521,11 +496,11 @@ class NgpCombobox {
521
496
  * Open the dropdown.
522
497
  * @internal
523
498
  */
524
- openDropdown() {
499
+ async openDropdown() {
525
500
  if (this.state.disabled() || this.open()) {
526
501
  return;
527
502
  }
528
- this.portal()?.attach();
503
+ await this.portal()?.show();
529
504
  // if there is a selected option(s), set the active descendant to the first selected option
530
505
  const selectedOption = this.options().find(option => this.isOptionSelected(option));
531
506
  // if there is no selected option, set the active descendant to the first option
@@ -568,10 +543,14 @@ class NgpCombobox {
568
543
  * @internal
569
544
  */
570
545
  selectOption(option) {
571
- if (this.state.disabled() || this.isOptionSelected(option)) {
546
+ if (this.state.disabled()) {
572
547
  return;
573
548
  }
574
549
  if (this.state.multiple()) {
550
+ // if the option is already selected, do nothing
551
+ if (this.isOptionSelected(option)) {
552
+ return;
553
+ }
575
554
  const value = [...this.state.value(), option.value()];
576
555
  // add the option to the value
577
556
  this.state.value.set(value);
@@ -733,14 +712,14 @@ class NgpCombobox {
733
712
  this.options.update(options => options.filter(o => o !== option));
734
713
  }
735
714
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpCombobox, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
736
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpCombobox, isStandalone: true, selector: "[ngpCombobox]", inputs: { value: { classPropertyName: "value", publicName: "ngpComboboxValue", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "ngpComboboxMultiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpComboboxDisabled", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "ngpComboboxCompareWith", isSignal: true, isRequired: false, transformFunction: null }, dropdownPosition: { classPropertyName: "dropdownPosition", publicName: "ngpComboboxDropdownPosition", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "ngpComboboxValueChange", openChange: "ngpComboboxOpenChange" }, host: { properties: { "attr.data-open": "state.open() ? \"\" : undefined", "attr.data-disabled": "state.disabled() ? \"\" : undefined", "attr.data-multiple": "state.multiple() ? \"\" : undefined" } }, providers: [provideComboboxState()], exportAs: ["ngpCombobox"], ngImport: i0 }); }
715
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpCombobox, isStandalone: true, selector: "[ngpCombobox]", inputs: { value: { classPropertyName: "value", publicName: "ngpComboboxValue", isSignal: true, isRequired: false, transformFunction: null }, multiple: { classPropertyName: "multiple", publicName: "ngpComboboxMultiple", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpComboboxDisabled", isSignal: true, isRequired: false, transformFunction: null }, compareWith: { classPropertyName: "compareWith", publicName: "ngpComboboxCompareWith", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "ngpComboboxDropdownPlacement", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { valueChange: "ngpComboboxValueChange", openChange: "ngpComboboxOpenChange" }, host: { properties: { "attr.data-open": "state.open() ? \"\" : undefined", "attr.data-disabled": "state.disabled() ? \"\" : undefined", "attr.data-multiple": "state.multiple() ? \"\" : undefined" } }, providers: [provideComboboxState(), provideExitAnimationManager()], exportAs: ["ngpCombobox"], ngImport: i0 }); }
737
716
  }
738
717
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpCombobox, decorators: [{
739
718
  type: Directive,
740
719
  args: [{
741
720
  selector: '[ngpCombobox]',
742
721
  exportAs: 'ngpCombobox',
743
- providers: [provideComboboxState()],
722
+ providers: [provideComboboxState(), provideExitAnimationManager()],
744
723
  host: {
745
724
  '[attr.data-open]': 'state.open() ? "" : undefined',
746
725
  '[attr.data-disabled]': 'state.disabled() ? "" : undefined',