@taiga-ui/core 5.23.0 → 5.24.0-canary.51d7c08

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 (75) hide show
  1. package/classes/accessors.d.ts +6 -1
  2. package/components/cell/cell-stretch.directive.d.ts +1 -1
  3. package/components/data-list/option.directive.d.ts +1 -1
  4. package/components/textfield/select-like.directive.d.ts +2 -1
  5. package/components/textfield/textfield.component.d.ts +2 -0
  6. package/fesm2022/taiga-ui-core-classes.mjs +23 -7
  7. package/fesm2022/taiga-ui-core-classes.mjs.map +1 -1
  8. package/fesm2022/taiga-ui-core-components-button.mjs +2 -2
  9. package/fesm2022/taiga-ui-core-components-button.mjs.map +1 -1
  10. package/fesm2022/taiga-ui-core-components-calendar.mjs +1 -1
  11. package/fesm2022/taiga-ui-core-components-calendar.mjs.map +1 -1
  12. package/fesm2022/taiga-ui-core-components-cell.mjs +6 -9
  13. package/fesm2022/taiga-ui-core-components-cell.mjs.map +1 -1
  14. package/fesm2022/taiga-ui-core-components-checkbox.mjs +2 -2
  15. package/fesm2022/taiga-ui-core-components-checkbox.mjs.map +1 -1
  16. package/fesm2022/taiga-ui-core-components-data-list.mjs +7 -7
  17. package/fesm2022/taiga-ui-core-components-data-list.mjs.map +1 -1
  18. package/fesm2022/taiga-ui-core-components-icon.mjs +2 -2
  19. package/fesm2022/taiga-ui-core-components-icon.mjs.map +1 -1
  20. package/fesm2022/taiga-ui-core-components-input.mjs +2 -1
  21. package/fesm2022/taiga-ui-core-components-input.mjs.map +1 -1
  22. package/fesm2022/taiga-ui-core-components-label.mjs +3 -3
  23. package/fesm2022/taiga-ui-core-components-label.mjs.map +1 -1
  24. package/fesm2022/taiga-ui-core-components-link.mjs +2 -2
  25. package/fesm2022/taiga-ui-core-components-link.mjs.map +1 -1
  26. package/fesm2022/taiga-ui-core-components-notification.mjs +2 -2
  27. package/fesm2022/taiga-ui-core-components-notification.mjs.map +1 -1
  28. package/fesm2022/taiga-ui-core-components-radio.mjs +2 -2
  29. package/fesm2022/taiga-ui-core-components-radio.mjs.map +1 -1
  30. package/fesm2022/taiga-ui-core-components-root.mjs +1 -1
  31. package/fesm2022/taiga-ui-core-components-root.mjs.map +1 -1
  32. package/fesm2022/taiga-ui-core-components-scrollbar.mjs +5 -5
  33. package/fesm2022/taiga-ui-core-components-scrollbar.mjs.map +1 -1
  34. package/fesm2022/taiga-ui-core-components-textfield.mjs +25 -10
  35. package/fesm2022/taiga-ui-core-components-textfield.mjs.map +1 -1
  36. package/fesm2022/taiga-ui-core-components-title.mjs +3 -3
  37. package/fesm2022/taiga-ui-core-components-title.mjs.map +1 -1
  38. package/fesm2022/taiga-ui-core-directives-appearance.mjs +3 -3
  39. package/fesm2022/taiga-ui-core-directives-appearance.mjs.map +1 -1
  40. package/fesm2022/taiga-ui-core-directives-group.mjs +3 -3
  41. package/fesm2022/taiga-ui-core-directives-group.mjs.map +1 -1
  42. package/fesm2022/taiga-ui-core-directives-icons.mjs +3 -3
  43. package/fesm2022/taiga-ui-core-directives-icons.mjs.map +1 -1
  44. package/fesm2022/taiga-ui-core-portals-alert.mjs +3 -3
  45. package/fesm2022/taiga-ui-core-portals-alert.mjs.map +1 -1
  46. package/fesm2022/taiga-ui-core-portals-dialog.mjs +2 -2
  47. package/fesm2022/taiga-ui-core-portals-dialog.mjs.map +1 -1
  48. package/fesm2022/taiga-ui-core-portals-dropdown.mjs +191 -112
  49. package/fesm2022/taiga-ui-core-portals-dropdown.mjs.map +1 -1
  50. package/fesm2022/taiga-ui-core-portals-hint.mjs +171 -82
  51. package/fesm2022/taiga-ui-core-portals-hint.mjs.map +1 -1
  52. package/fesm2022/taiga-ui-core-portals-modal.mjs +3 -3
  53. package/fesm2022/taiga-ui-core-portals-modal.mjs.map +1 -1
  54. package/fesm2022/taiga-ui-core-tokens.mjs +4 -2
  55. package/fesm2022/taiga-ui-core-tokens.mjs.map +1 -1
  56. package/package.json +12 -12
  57. package/portals/dropdown/dropdown-anchor.directive.d.ts +6 -12
  58. package/portals/dropdown/dropdown-anchored.directive.d.ts +16 -0
  59. package/portals/dropdown/dropdown-context.directive.d.ts +5 -1
  60. package/portals/dropdown/dropdown-selection.directive.d.ts +5 -3
  61. package/portals/dropdown/dropdown.component.d.ts +2 -2
  62. package/portals/dropdown/dropdown.directive.d.ts +6 -4
  63. package/portals/dropdown/dropdown.providers.d.ts +1 -0
  64. package/portals/dropdown/index.d.ts +1 -0
  65. package/portals/hint/hint-anchor.directive.d.ts +12 -0
  66. package/portals/hint/hint-anchored.directive.d.ts +17 -0
  67. package/portals/hint/hint-host.directive.d.ts +4 -1
  68. package/portals/hint/hint-hover.directive.d.ts +1 -1
  69. package/portals/hint/hint-pointer.directive.d.ts +6 -1
  70. package/portals/hint/hint.component.d.ts +3 -10
  71. package/portals/hint/hint.d.ts +1 -2
  72. package/portals/hint/hint.directive.d.ts +5 -4
  73. package/portals/hint/index.d.ts +2 -0
  74. package/tokens/anchor-support.d.ts +2 -0
  75. package/tokens/index.d.ts +1 -0
@@ -1,15 +1,15 @@
1
1
  import { tuiProvide, tuiDirectiveBinding, tuiCreateOptions } from '@taiga-ui/cdk/utils/di';
2
2
  import { coerceArray } from '@angular/cdk/coercion';
3
3
  import * as i0 from '@angular/core';
4
- import { Injectable, Directive, InjectionToken, Optional, Self, SkipSelf, inject, forwardRef, computed, ChangeDetectionStrategy, Component, input, effect, INJECTOR, ChangeDetectorRef, signal, TemplateRef, ElementRef, contentChild, model, PLATFORM_ID, ViewContainerRef } from '@angular/core';
5
- import { outputFromObservable, takeUntilDestroyed, toObservable } from '@angular/core/rxjs-interop';
4
+ import { Injectable, Directive, InjectionToken, Optional, Self, SkipSelf, inject, computed, ChangeDetectionStrategy, Component, input, effect, ElementRef, INJECTOR, ChangeDetectorRef, signal, TemplateRef, contentChild, model, PLATFORM_ID, ViewContainerRef, afterNextRender } from '@angular/core';
5
+ import { takeUntilDestroyed, outputFromObservable, toObservable } from '@angular/core/rxjs-interop';
6
6
  import { tuiZonefreeScheduler, tuiIfMap, tuiCloseWatcher, tuiTypedFromEvent, tuiStopPropagation, tuiZoneOptimized } from '@taiga-ui/cdk/observables';
7
7
  import { tuiInjectElement, tuiGetActualTarget, tuiIsElement, tuiIsElementEditable, tuiIsHTMLElement, tuiPointToClientRect, tuiIsTextNode, tuiIsTextfield } from '@taiga-ui/cdk/utils/dom';
8
- import { TuiDriverDirective, TuiPositionAccessor, tuiFallbackAccessor, TuiRectAccessor, tuiPositionAccessorFor, tuiRectAccessorFor, tuiAsVehicle, tuiAsDriver, tuiAsRectAccessor, TuiDriver, tuiAsPositionAccessor } from '@taiga-ui/core/classes';
8
+ import { TuiDriverDirective, TuiRectAccessor, tuiProvideAccessor, TuiPositionAccessor, tuiAsRectAccessor, tuiInjectAccessor, tuiAsPositionAccessor, tuiAsVehicle, tuiAsDriver, TuiDriver } from '@taiga-ui/core/classes';
9
9
  import { TuiPopupService } from '@taiga-ui/core/portals/popup';
10
10
  import { tuiCheckFixedPosition, tuiGetWordRange } from '@taiga-ui/core/utils/dom';
11
11
  import { PolymorpheusOutlet, PolymorpheusComponent, PolymorpheusTemplate } from '@taiga-ui/polymorpheus';
12
- import { BehaviorSubject, Subject, distinctUntilChanged, takeWhile, map, throttleTime, merge, filter, EMPTY, switchMap, delay, startWith, takeUntil, fromEvent, of, tap, share, combineLatest } from 'rxjs';
12
+ import { BehaviorSubject, takeWhile, map, Subject, distinctUntilChanged, throttleTime, merge, filter, EMPTY, switchMap, delay, startWith, takeUntil, fromEvent, of, tap, share, combineLatest } from 'rxjs';
13
13
  import * as i1 from '@taiga-ui/cdk/directives/active-zone';
14
14
  import { TuiActiveZone } from '@taiga-ui/cdk/directives/active-zone';
15
15
  import * as i2 from '@taiga-ui/cdk/directives/animated';
@@ -99,84 +99,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
99
99
  }]
100
100
  }] });
101
101
 
102
- class TuiDropdownPosition extends TuiPositionAccessor {
103
- constructor() {
104
- super(...arguments);
105
- this.el = tuiInjectElement();
106
- this.options = inject(TUI_DROPDOWN_OPTIONS);
107
- this.viewport = inject(TUI_VIEWPORT);
108
- this.direction = new Subject();
109
- this.type = 'dropdown';
110
- this.accessor = tuiFallbackAccessor('dropdown')(inject(TuiRectAccessor, { self: true, optional: true }), { getClientRect: () => this.el.getBoundingClientRect() });
111
- this.tuiDropdownDirectionChange = outputFromObservable(this.direction.pipe(distinctUntilChanged()));
112
- }
113
- getPosition({ width, height }) {
114
- if (!width && !height) {
115
- this.previous = undefined;
116
- }
117
- const hostRect = this.accessor.getClientRect();
118
- const viewportRect = this.viewport.getClientRect();
119
- const { minHeight, direction, offset, limitWidth } = this.options;
120
- const align = this.getAlign(this.options.align);
121
- const viewport = {
122
- top: viewportRect.top - offset,
123
- bottom: viewportRect.bottom + offset,
124
- right: viewportRect.right - offset,
125
- left: viewportRect.left + offset,
126
- };
127
- const previous = this.previous || direction || 'bottom';
128
- const available = {
129
- top: hostRect.top - 2 * offset - viewport.top,
130
- bottom: viewport.bottom - hostRect.bottom - 2 * offset,
131
- };
132
- const rectWidth = limitWidth === 'fixed' ? hostRect.width : width;
133
- const right = Math.max(hostRect.right - rectWidth, offset);
134
- const left = hostRect.left + width < viewport.right ? hostRect.left : right;
135
- const position = {
136
- top: hostRect.top - offset - height,
137
- bottom: hostRect.bottom + offset,
138
- right: Math.max(viewport.left, right),
139
- center: hostRect.left + hostRect.width / 2 + width / 2 < viewport.right
140
- ? hostRect.left + hostRect.width / 2 - width / 2
141
- : right,
142
- left: Math.max(viewport.left, left),
143
- };
144
- const better = available.top > available.bottom ? 'top' : 'bottom';
145
- if ((available[previous] > minHeight && direction) ||
146
- available[previous] > height) {
147
- this.direction.next(previous);
148
- return [position[align], position[previous]];
149
- }
150
- this.previous = better;
151
- this.direction.next(better);
152
- return [position[align], position[better]];
153
- }
154
- getAlign(align) {
155
- const rtl = this.el.matches('[dir="rtl"] :scope');
156
- if (rtl && align === 'start') {
157
- return 'right';
158
- }
159
- if (rtl && align === 'end') {
160
- return 'left';
161
- }
162
- if (align === 'center') {
163
- return 'center';
164
- }
165
- return align === 'end' ? 'right' : 'left';
166
- }
167
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPosition, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
168
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownPosition, isStandalone: true, outputs: { tuiDropdownDirectionChange: "tuiDropdownDirectionChange" }, usesInheritance: true, ngImport: i0 }); }
169
- }
170
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPosition, decorators: [{
171
- type: Directive
172
- }] });
173
-
174
102
  const MAX_WIDTH_GAP = 16; // 8px min gap from each side
175
- class TuiDropdownAnchor {
103
+ class TuiDropdownAnchored {
176
104
  constructor() {
177
105
  this.el = tuiInjectElement();
178
106
  this.directive = inject(TuiDropdownDirective);
179
- this.accessor = this.directive.accessor;
107
+ this.accessor = inject(TuiRectAccessor);
180
108
  this.viewport = inject(TUI_VIEWPORT);
181
109
  this.vvs = inject(TuiVisualViewportService);
182
110
  this.options = inject(TUI_DROPDOWN_OPTIONS);
@@ -215,20 +143,20 @@ class TuiDropdownAnchor {
215
143
  maxWidth: tuiPx(Math.round(viewport.width / zoom) - MAX_WIDTH_GAP),
216
144
  };
217
145
  }
218
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
219
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownAnchor, isStandalone: true, providers: [
146
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchored, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
147
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownAnchored, isStandalone: true, providers: [
220
148
  TuiPositionService,
221
- tuiPositionAccessorFor('dropdown', TuiDropdownPosition),
222
- tuiRectAccessorFor('dropdown', forwardRef(() => TuiDropdownDirective)),
149
+ tuiProvideAccessor(TuiPositionAccessor, 'dropdown'),
150
+ tuiProvideAccessor(TuiRectAccessor, 'dropdown'),
223
151
  ], ngImport: i0 }); }
224
152
  }
225
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, decorators: [{
153
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchored, decorators: [{
226
154
  type: Directive,
227
155
  args: [{
228
156
  providers: [
229
157
  TuiPositionService,
230
- tuiPositionAccessorFor('dropdown', TuiDropdownPosition),
231
- tuiRectAccessorFor('dropdown', forwardRef(() => TuiDropdownDirective)),
158
+ tuiProvideAccessor(TuiPositionAccessor, 'dropdown'),
159
+ tuiProvideAccessor(TuiRectAccessor, 'dropdown'),
232
160
  ],
233
161
  }]
234
162
  }] });
@@ -248,11 +176,11 @@ class TuiDropdownComponent {
248
176
  this.close = () => this.directive.toggle(false);
249
177
  }
250
178
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
251
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownComponent, isStandalone: true, selector: "tui-dropdown", host: { properties: { "attr.data-appearance": "options.appearance", "attr.tuiTheme": "theme()" } }, hostDirectives: [{ directive: i1.TuiActiveZone }, { directive: i2.TuiAnimated }, { directive: TuiDropdownAnchor }], ngImport: i0, template: "<tui-scrollbar class=\"t-scroll\">\n <div\n *polymorpheusOutlet=\"directive.content() as text; context: {$implicit: close}\"\n class=\"t-primitive\"\n >\n {{ text }}\n </div>\n</tui-scrollbar>\n", styles: [":host{position:absolute;display:flex;box-shadow:var(--tui-shadow-medium);color:var(--tui-text-primary);background:var(--tui-background-elevation-1);border-radius:var(--tui-radius-m);overflow:hidden;border:1px solid var(--tui-border-normal);box-sizing:border-box;isolation:isolate;pointer-events:auto;--tui-from: translateY(-1rem)}:host:has(tui-data-list[data-size=l]){border-radius:var(--tui-radius-l)}:host.tui-enter,:host.tui-leave{animation-name:tuiFade,tuiSlide;animation-duration:calc(var(--tui-duration) / 2);pointer-events:none}:host:not([style*=top]){visibility:hidden}.t-scroll{flex-grow:1;max-inline-size:calc(100% + 2px);inline-size:max-content;overscroll-behavior:none;margin:-1px}.t-primitive{padding:1rem}\n"], dependencies: [{ kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }, { kind: "component", type: TuiScrollbar, selector: "tui-scrollbar" }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
179
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownComponent, isStandalone: true, selector: "tui-dropdown", host: { properties: { "attr.data-appearance": "options.appearance", "attr.tuiTheme": "theme()" } }, hostDirectives: [{ directive: i1.TuiActiveZone }, { directive: i2.TuiAnimated }, { directive: TuiDropdownAnchored }], ngImport: i0, template: "<tui-scrollbar class=\"t-scroll\">\n <div\n *polymorpheusOutlet=\"directive.content() as text; context: {$implicit: close}\"\n class=\"t-primitive\"\n >\n {{ text }}\n </div>\n</tui-scrollbar>\n", styles: [":host{position:absolute;display:flex;box-shadow:var(--tui-shadow-medium);color:var(--tui-text-primary);background:var(--tui-background-elevation-1);border-radius:var(--tui-radius-m);overflow:hidden;border:1px solid var(--tui-border-normal);box-sizing:border-box;isolation:isolate;pointer-events:auto;--tui-from: translateY(-1rem)}:host:has(tui-data-list[data-size=l]){border-radius:var(--tui-radius-l)}:host.tui-enter,:host.tui-leave{animation-name:tuiFade,tuiSlide;animation-duration:calc(var(--tui-duration) / 2);pointer-events:none}:host:not([style*=top]){visibility:hidden}.t-scroll{flex-grow:1;max-inline-size:calc(100% + 2px);inline-size:max-content;overscroll-behavior:none;margin:-1px}.t-primitive{padding:1rem}\n"], dependencies: [{ kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }, { kind: "component", type: TuiScrollbar, selector: "tui-scrollbar" }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
252
180
  }
253
181
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownComponent, decorators: [{
254
182
  type: Component,
255
- args: [{ selector: 'tui-dropdown', imports: [PolymorpheusOutlet, TuiScrollbar], changeDetection: ChangeDetectionStrategy.Default, hostDirectives: [TuiActiveZone, TuiAnimated, TuiDropdownAnchor], host: {
183
+ args: [{ selector: 'tui-dropdown', imports: [PolymorpheusOutlet, TuiScrollbar], changeDetection: ChangeDetectionStrategy.Default, hostDirectives: [TuiActiveZone, TuiAnimated, TuiDropdownAnchored], host: {
256
184
  '[attr.data-appearance]': 'options.appearance',
257
185
  '[attr.tuiTheme]': 'theme()',
258
186
  }, template: "<tui-scrollbar class=\"t-scroll\">\n <div\n *polymorpheusOutlet=\"directive.content() as text; context: {$implicit: close}\"\n class=\"t-primitive\"\n >\n {{ text }}\n </div>\n</tui-scrollbar>\n", styles: [":host{position:absolute;display:flex;box-shadow:var(--tui-shadow-medium);color:var(--tui-text-primary);background:var(--tui-background-elevation-1);border-radius:var(--tui-radius-m);overflow:hidden;border:1px solid var(--tui-border-normal);box-sizing:border-box;isolation:isolate;pointer-events:auto;--tui-from: translateY(-1rem)}:host:has(tui-data-list[data-size=l]){border-radius:var(--tui-radius-l)}:host.tui-enter,:host.tui-leave{animation-name:tuiFade,tuiSlide;animation-duration:calc(var(--tui-duration) / 2);pointer-events:none}:host:not([style*=top]){visibility:hidden}.t-scroll{flex-grow:1;max-inline-size:calc(100% + 2px);inline-size:max-content;overscroll-behavior:none;margin:-1px}.t-primitive{padding:1rem}\n"] }]
@@ -264,6 +192,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
264
192
  const TUI_DROPDOWN_COMPONENT = new InjectionToken(ngDevMode ? 'TUI_DROPDOWN_COMPONENT' : '', { factory: () => TuiDropdownComponent });
265
193
  const TUI_DROPDOWN_CONTEXT = new InjectionToken(ngDevMode ? 'TUI_DROPDOWN_CONTEXT' : '');
266
194
  const TUI_DROPDOWN_HOST = new InjectionToken(ngDevMode ? 'TUI_DROPDOWN_HOST' : '');
195
+ const TUI_DROPDOWN_ANCHOR = new InjectionToken(ngDevMode ? 'TUI_DROPDOWN_ANCHOR' : '');
267
196
 
268
197
  class TuiDropdownA11y {
269
198
  constructor() {
@@ -296,6 +225,111 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
296
225
  args: [{ selector: '[tuiDropdownA11y]' }]
297
226
  }] });
298
227
 
228
+ class TuiDropdownAnchor extends TuiRectAccessor {
229
+ constructor() {
230
+ super(...arguments);
231
+ this.el = tuiInjectElement();
232
+ this.anchor = `--${tuiGenerateId()}`;
233
+ this.type = 'dropdown';
234
+ }
235
+ getClientRect() {
236
+ return this.el.getBoundingClientRect();
237
+ }
238
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
239
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownAnchor, isStandalone: true, host: { properties: { "attr.data-tui-anchor": "anchor", "style.anchor-name": "anchor" } }, providers: [
240
+ tuiAsRectAccessor(TuiDropdownAnchor),
241
+ tuiProvide(TUI_DROPDOWN_HOST, ElementRef),
242
+ tuiProvide(TUI_DROPDOWN_ANCHOR, ElementRef),
243
+ ], usesInheritance: true, ngImport: i0 }); }
244
+ }
245
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, decorators: [{
246
+ type: Directive,
247
+ args: [{
248
+ providers: [
249
+ tuiAsRectAccessor(TuiDropdownAnchor),
250
+ tuiProvide(TUI_DROPDOWN_HOST, ElementRef),
251
+ tuiProvide(TUI_DROPDOWN_ANCHOR, ElementRef),
252
+ ],
253
+ host: {
254
+ '[attr.data-tui-anchor]': 'anchor',
255
+ '[style.anchor-name]': 'anchor',
256
+ },
257
+ }]
258
+ }] });
259
+
260
+ class TuiDropdownPosition extends TuiPositionAccessor {
261
+ constructor() {
262
+ super(...arguments);
263
+ this.el = tuiInjectElement();
264
+ this.options = inject(TUI_DROPDOWN_OPTIONS);
265
+ this.viewport = inject(TUI_VIEWPORT);
266
+ this.direction = new Subject();
267
+ this.type = 'dropdown';
268
+ this.accessor = tuiInjectAccessor(TuiRectAccessor, 'dropdown');
269
+ this.tuiDropdownDirectionChange = outputFromObservable(this.direction.pipe(distinctUntilChanged()));
270
+ }
271
+ getPosition({ width, height }) {
272
+ if (!width && !height) {
273
+ this.previous = undefined;
274
+ }
275
+ const hostRect = this.accessor.getClientRect();
276
+ const viewportRect = this.viewport.getClientRect();
277
+ const { minHeight, direction, offset, limitWidth } = this.options;
278
+ const align = this.getAlign(this.options.align);
279
+ const viewport = {
280
+ top: viewportRect.top - offset,
281
+ bottom: viewportRect.bottom + offset,
282
+ right: viewportRect.right - offset,
283
+ left: viewportRect.left + offset,
284
+ };
285
+ const previous = this.previous || direction || 'bottom';
286
+ const available = {
287
+ top: hostRect.top - 2 * offset - viewport.top,
288
+ bottom: viewport.bottom - hostRect.bottom - 2 * offset,
289
+ };
290
+ const rectWidth = limitWidth === 'fixed' ? hostRect.width : width;
291
+ const right = Math.max(hostRect.right - rectWidth, offset);
292
+ const left = hostRect.left + width < viewport.right ? hostRect.left : right;
293
+ const position = {
294
+ top: hostRect.top - offset - height,
295
+ bottom: hostRect.bottom + offset,
296
+ right: Math.max(viewport.left, right),
297
+ center: hostRect.left + hostRect.width / 2 + width / 2 < viewport.right
298
+ ? hostRect.left + hostRect.width / 2 - width / 2
299
+ : right,
300
+ left: Math.max(viewport.left, left),
301
+ };
302
+ const better = available.top > available.bottom ? 'top' : 'bottom';
303
+ if ((available[previous] > minHeight && direction) ||
304
+ available[previous] > height) {
305
+ this.direction.next(previous);
306
+ return [position[align], position[previous]];
307
+ }
308
+ this.previous = better;
309
+ this.direction.next(better);
310
+ return [position[align], position[better]];
311
+ }
312
+ getAlign(align) {
313
+ const rtl = this.el.matches('[dir="rtl"] :scope');
314
+ if (rtl && align === 'start') {
315
+ return 'right';
316
+ }
317
+ if (rtl && align === 'end') {
318
+ return 'left';
319
+ }
320
+ if (align === 'center') {
321
+ return 'center';
322
+ }
323
+ return align === 'end' ? 'right' : 'left';
324
+ }
325
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPosition, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
326
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.25", type: TuiDropdownPosition, isStandalone: true, outputs: { tuiDropdownDirectionChange: "tuiDropdownDirectionChange" }, providers: [tuiAsPositionAccessor(TuiDropdownPosition)], usesInheritance: true, ngImport: i0 }); }
327
+ }
328
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPosition, decorators: [{
329
+ type: Directive,
330
+ args: [{ providers: [tuiAsPositionAccessor(TuiDropdownPosition)] }]
331
+ }] });
332
+
299
333
  class TuiDropdownDirective {
300
334
  constructor() {
301
335
  this.injector = inject(INJECTOR);
@@ -325,11 +359,12 @@ class TuiDropdownDirective {
325
359
  : content,
326
360
  });
327
361
  }
362
+ /** @deprecated remove in v6 */
328
363
  get accessor() {
329
364
  const accessors = this.injector.get(TuiRectAccessor, null, {
330
365
  self: true,
331
366
  });
332
- return tuiFallbackAccessor('dropdown')(accessors, this);
367
+ return ([...(accessors || [])].reverse().find(({ type }) => type === 'dropdown') || this);
333
368
  }
334
369
  get position() {
335
370
  return tuiCheckFixedPosition(this.el) ? 'fixed' : 'absolute';
@@ -357,21 +392,16 @@ class TuiDropdownDirective {
357
392
  this.drivers.forEach((driver) => driver?.next(show));
358
393
  }
359
394
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
360
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.25", type: TuiDropdownDirective, isStandalone: true, selector: "[tuiDropdown]:not(ng-container):not(ng-template)", inputs: { content: { classPropertyName: "content", publicName: "tuiDropdown", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.tui-dropdown-open": "ref()" } }, providers: [
361
- tuiAsVehicle(TuiDropdownDirective),
362
- tuiProvide(TUI_DROPDOWN_HOST, ElementRef),
363
- ], exportAs: ["tuiDropdown"], hostDirectives: [{ directive: TuiDropdownDriverDirective }, { directive: TuiDropdownA11y, inputs: ["tuiDropdownRole", "tuiDropdownRole"] }, { directive: TuiDropdownPosition, outputs: ["tuiDropdownDirectionChange", "tuiDropdownDirectionChange"] }], ngImport: i0 }); }
395
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.25", type: TuiDropdownDirective, isStandalone: true, selector: "[tuiDropdown]:not(ng-container):not(ng-template)", inputs: { content: { classPropertyName: "content", publicName: "tuiDropdown", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class.tui-dropdown-open": "ref()" } }, providers: [tuiAsVehicle(TuiDropdownDirective)], exportAs: ["tuiDropdown"], hostDirectives: [{ directive: TuiDropdownAnchor }, { directive: TuiDropdownDriverDirective }, { directive: TuiDropdownA11y, inputs: ["tuiDropdownRole", "tuiDropdownRole"] }, { directive: TuiDropdownPosition, outputs: ["tuiDropdownDirectionChange", "tuiDropdownDirectionChange"] }], ngImport: i0 }); }
364
396
  }
365
397
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownDirective, decorators: [{
366
398
  type: Directive,
367
399
  args: [{
368
400
  selector: '[tuiDropdown]:not(ng-container):not(ng-template)',
369
- providers: [
370
- tuiAsVehicle(TuiDropdownDirective),
371
- tuiProvide(TUI_DROPDOWN_HOST, ElementRef),
372
- ],
401
+ providers: [tuiAsVehicle(TuiDropdownDirective)],
373
402
  exportAs: 'tuiDropdown',
374
403
  hostDirectives: [
404
+ TuiDropdownAnchor,
375
405
  TuiDropdownDriverDirective,
376
406
  { directive: TuiDropdownA11y, inputs: ['tuiDropdownRole'] },
377
407
  {
@@ -558,6 +588,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
558
588
  args: [{ selector: 'ng-template[tuiDropdown]' }]
559
589
  }], ctorParameters: () => [] });
560
590
 
591
+ const STYLE = {
592
+ position: 'fixed',
593
+ blockSize: '1px',
594
+ inlineSize: '1px',
595
+ pointerEvents: 'none',
596
+ };
561
597
  class TuiDropdownContext extends TuiRectAccessor {
562
598
  constructor() {
563
599
  super(...arguments);
@@ -580,12 +616,27 @@ class TuiDropdownContext extends TuiRectAccessor {
580
616
  this.currentRect = EMPTY_CLIENT_RECT;
581
617
  });
582
618
  this.type = 'dropdown';
619
+ this.nativeElement = this.doc.createElement('div');
620
+ }
621
+ ngAfterViewInit() {
622
+ const anchorName = `--${tuiGenerateId()}`;
623
+ const positionAnchor = this.el.getAttribute('data-tui-anchor');
624
+ const style = { ...STYLE, positionAnchor, anchorName };
625
+ Object.assign(this.nativeElement.style, style);
626
+ this.nativeElement.setAttribute('data-tui-anchor', anchorName);
627
+ }
628
+ ngOnDestroy() {
629
+ this.nativeElement.parentNode?.removeChild(this.nativeElement);
583
630
  }
584
631
  getClientRect() {
585
632
  return this.currentRect;
586
633
  }
587
634
  onContextMenu(x, y) {
635
+ const { top, left } = this.el.getBoundingClientRect();
588
636
  this.currentRect = tuiPointToClientRect(x, y);
637
+ this.nativeElement.style.top = `calc(anchor(top) + ${y - top}px)`;
638
+ this.nativeElement.style.left = `calc(anchor(left) + ${x - left}px)`;
639
+ this.doc.body.appendChild(this.nativeElement);
589
640
  this.driver.next(true);
590
641
  }
591
642
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownContext, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
@@ -594,6 +645,7 @@ class TuiDropdownContext extends TuiRectAccessor {
594
645
  TuiDropdownDriver,
595
646
  tuiAsDriver(TuiDropdownDriver),
596
647
  tuiAsRectAccessor(TuiDropdownContext),
648
+ tuiProvide(TUI_DROPDOWN_ANCHOR, TuiDropdownContext),
597
649
  ], usesInheritance: true, ngImport: i0 }); }
598
650
  }
599
651
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownContext, decorators: [{
@@ -605,6 +657,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
605
657
  TuiDropdownDriver,
606
658
  tuiAsDriver(TuiDropdownDriver),
607
659
  tuiAsRectAccessor(TuiDropdownContext),
660
+ tuiProvide(TUI_DROPDOWN_ANCHOR, TuiDropdownContext),
608
661
  ],
609
662
  host: {
610
663
  '[style.-webkit-touch-callout]': 'userSelect()',
@@ -727,21 +780,21 @@ class TuiDropdownPositionSided extends TuiPositionAccessor {
727
780
  super(...arguments);
728
781
  this.options = inject(TUI_DROPDOWN_OPTIONS);
729
782
  this.viewport = inject(TUI_VIEWPORT);
730
- this.vertical = inject(TuiDropdownPosition);
783
+ this.vertical = inject(TuiDropdownPosition, { optional: true });
731
784
  this.previous = this.options.direction || 'bottom';
732
785
  this.tuiDropdownSided = input('');
733
786
  this.tuiDropdownSidedOffset = input(4);
734
787
  this.type = 'dropdown';
735
788
  }
736
789
  getPosition(rect) {
737
- if (this.tuiDropdownSided() === false) {
790
+ if (this.tuiDropdownSided() === false && this.vertical) {
738
791
  return this.vertical.getPosition(rect);
739
792
  }
740
793
  const { height, width } = rect;
741
- const hostRect = this.vertical.accessor?.getClientRect() ?? EMPTY_CLIENT_RECT;
794
+ const hostRect = this.vertical?.accessor.getClientRect() ?? EMPTY_CLIENT_RECT;
742
795
  const viewport = this.viewport.getClientRect();
743
796
  const { direction, offset } = this.options;
744
- const adjusted = this.vertical.getAlign(this.options.align);
797
+ const adjusted = this.vertical?.getAlign(this.options.align) || 'center';
745
798
  const align = adjusted === 'center' ? 'left' : adjusted;
746
799
  const available = {
747
800
  top: hostRect.bottom - viewport.top,
@@ -760,21 +813,21 @@ class TuiDropdownPositionSided extends TuiPositionAccessor {
760
813
  const left = available[align] > width ? position[align] : maxLeft;
761
814
  if ((available[this.previous] > height && direction) ||
762
815
  this.previous === better) {
763
- this.vertical.direction.next(this.previous);
816
+ this.vertical?.direction.next(this.previous);
764
817
  return [left, position[this.previous]];
765
818
  }
766
819
  this.previous = better;
767
- this.vertical.direction.next(better);
820
+ this.vertical?.direction.next(better);
768
821
  return [left, position[better]];
769
822
  }
770
823
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPositionSided, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
771
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.25", type: TuiDropdownPositionSided, isStandalone: true, selector: "[tuiDropdownSided]", inputs: { tuiDropdownSided: { classPropertyName: "tuiDropdownSided", publicName: "tuiDropdownSided", isSignal: true, isRequired: false, transformFunction: null }, tuiDropdownSidedOffset: { classPropertyName: "tuiDropdownSidedOffset", publicName: "tuiDropdownSidedOffset", isSignal: true, isRequired: false, transformFunction: null } }, providers: [TuiDropdownPosition, tuiAsPositionAccessor(TuiDropdownPositionSided)], usesInheritance: true, ngImport: i0 }); }
824
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.25", type: TuiDropdownPositionSided, isStandalone: true, selector: "[tuiDropdownSided]", inputs: { tuiDropdownSided: { classPropertyName: "tuiDropdownSided", publicName: "tuiDropdownSided", isSignal: true, isRequired: false, transformFunction: null }, tuiDropdownSidedOffset: { classPropertyName: "tuiDropdownSidedOffset", publicName: "tuiDropdownSidedOffset", isSignal: true, isRequired: false, transformFunction: null } }, providers: [tuiAsPositionAccessor(TuiDropdownPositionSided)], usesInheritance: true, ngImport: i0 }); }
772
825
  }
773
826
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPositionSided, decorators: [{
774
827
  type: Directive,
775
828
  args: [{
776
829
  selector: '[tuiDropdownSided]',
777
- providers: [TuiDropdownPosition, tuiAsPositionAccessor(TuiDropdownPositionSided)],
830
+ providers: [tuiAsPositionAccessor(TuiDropdownPositionSided)],
778
831
  }]
779
832
  }] });
780
833
 
@@ -802,16 +855,35 @@ class TuiDropdownSelection extends TuiDriver {
802
855
  const contained = this.el.contains(range.commonAncestorContainer);
803
856
  const valid = contained && handler(this.range);
804
857
  const visible = valid || this.inDropdown(range);
805
- const active = tuiGetFocused(this.doc);
806
- const textfield = active && tuiIsTextfield(active) && this.el.contains(active);
858
+ const focus = tuiGetFocused(this.doc);
859
+ const textfield = focus && tuiIsTextfield(focus) && this.el.contains(focus);
860
+ this.updateAnchor();
807
861
  return visible && textfield ? this.isCaretVisible(this.range) : visible;
808
862
  }));
809
863
  this.range = isPlatformBrowser(inject(PLATFORM_ID))
810
864
  ? new Range()
811
865
  : {};
812
866
  this.type = 'dropdown';
867
+ this.nativeElement = this.doc.createElement('div');
813
868
  this.tuiDropdownSelection = input('');
814
869
  this.tuiDropdownSelectionPosition = input('selection');
870
+ afterNextRender(() => {
871
+ const anchorName = `--${tuiGenerateId()}`;
872
+ Object.assign(this.nativeElement.style, {
873
+ position: 'fixed',
874
+ pointerEvents: 'none',
875
+ positionAnchor: this.el.dataset.tuiAnchor,
876
+ anchorName,
877
+ });
878
+ this.nativeElement.dataset.tuiAnchor = anchorName;
879
+ this.doc.body.appendChild(this.nativeElement);
880
+ });
881
+ }
882
+ ngOnDestroy() {
883
+ this.nativeElement.parentNode?.removeChild(this.nativeElement);
884
+ if (this.ghost) {
885
+ this.ghostHost.removeChild(this.ghost);
886
+ }
815
887
  }
816
888
  getClientRect() {
817
889
  switch (this.tuiDropdownSelectionPosition()) {
@@ -830,11 +902,6 @@ class TuiDropdownSelection extends TuiDriver {
830
902
  return this.range.getBoundingClientRect();
831
903
  }
832
904
  }
833
- ngOnDestroy() {
834
- if (this.ghost) {
835
- this.ghostHost.removeChild(this.ghost);
836
- }
837
- }
838
905
  get ghostHost() {
839
906
  return this.el.querySelector('tui-textfield .t-ghost') || this.el;
840
907
  }
@@ -917,10 +984,21 @@ class TuiDropdownSelection extends TuiDriver {
917
984
  const threshold = lineHeight * 0.5;
918
985
  return visibleHeight >= threshold;
919
986
  }
987
+ updateAnchor() {
988
+ const rect = this.getClientRect();
989
+ const { top, left } = this.el.getBoundingClientRect();
990
+ Object.assign(this.nativeElement.style, {
991
+ top: `calc(anchor(top) + ${rect.top - top}px)`,
992
+ left: `calc(anchor(left) + ${rect.left - left}px)`,
993
+ blockSize: tuiPx(rect.height),
994
+ inlineSize: tuiPx(rect.width),
995
+ });
996
+ }
920
997
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownSelection, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
921
998
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.25", type: TuiDropdownSelection, isStandalone: true, selector: "[tuiDropdownSelection]", inputs: { tuiDropdownSelection: { classPropertyName: "tuiDropdownSelection", publicName: "tuiDropdownSelection", isSignal: true, isRequired: false, transformFunction: null }, tuiDropdownSelectionPosition: { classPropertyName: "tuiDropdownSelectionPosition", publicName: "tuiDropdownSelectionPosition", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
922
999
  tuiAsDriver(TuiDropdownSelection),
923
1000
  tuiAsRectAccessor(TuiDropdownSelection),
1001
+ tuiProvide(TUI_DROPDOWN_ANCHOR, TuiDropdownSelection),
924
1002
  ], usesInheritance: true, ngImport: i0 }); }
925
1003
  }
926
1004
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownSelection, decorators: [{
@@ -930,6 +1008,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
930
1008
  providers: [
931
1009
  tuiAsDriver(TuiDropdownSelection),
932
1010
  tuiAsRectAccessor(TuiDropdownSelection),
1011
+ tuiProvide(TUI_DROPDOWN_ANCHOR, TuiDropdownSelection),
933
1012
  ],
934
1013
  }]
935
1014
  }], ctorParameters: () => [] });
@@ -971,5 +1050,5 @@ const TuiDropdown = [
971
1050
  * Generated bundle index. Do not edit.
972
1051
  */
973
1052
 
974
- export { TUI_DROPDOWN_COMPONENT, TUI_DROPDOWN_CONTEXT, TUI_DROPDOWN_DEFAULT_OPTIONS, TUI_DROPDOWN_HOST, TUI_DROPDOWN_HOVER_DEFAULT_OPTIONS, TUI_DROPDOWN_HOVER_OPTIONS, TUI_DROPDOWN_OPTIONS, TuiDropdown, TuiDropdownA11y, TuiDropdownAnchor, TuiDropdownAuto, TuiDropdownClose, TuiDropdownComponent, TuiDropdownContent, TuiDropdownContext, TuiDropdownDirective, TuiDropdownDriver, TuiDropdownDriverDirective, TuiDropdownFixed, TuiDropdownHover, TuiDropdownManual, TuiDropdownOpen, TuiDropdownOptionsDirective, TuiDropdownPosition, TuiDropdownPositionSided, TuiDropdownSelection, TuiWithDropdownOpen, tuiDropdown, tuiDropdownEnabled, tuiDropdownHoverOptionsProvider, tuiDropdownOptionsProvider };
1053
+ export { TUI_DROPDOWN_ANCHOR, TUI_DROPDOWN_COMPONENT, TUI_DROPDOWN_CONTEXT, TUI_DROPDOWN_DEFAULT_OPTIONS, TUI_DROPDOWN_HOST, TUI_DROPDOWN_HOVER_DEFAULT_OPTIONS, TUI_DROPDOWN_HOVER_OPTIONS, TUI_DROPDOWN_OPTIONS, TuiDropdown, TuiDropdownA11y, TuiDropdownAnchor, TuiDropdownAnchored, TuiDropdownAuto, TuiDropdownClose, TuiDropdownComponent, TuiDropdownContent, TuiDropdownContext, TuiDropdownDirective, TuiDropdownDriver, TuiDropdownDriverDirective, TuiDropdownFixed, TuiDropdownHover, TuiDropdownManual, TuiDropdownOpen, TuiDropdownOptionsDirective, TuiDropdownPosition, TuiDropdownPositionSided, TuiDropdownSelection, TuiWithDropdownOpen, tuiDropdown, tuiDropdownEnabled, tuiDropdownHoverOptionsProvider, tuiDropdownOptionsProvider };
975
1054
  //# sourceMappingURL=taiga-ui-core-portals-dropdown.mjs.map