@taiga-ui/core 5.24.0 → 5.25.0-canary.2b025e7

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 (73) 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/scrollbar/scroll-controls.component.d.ts +1 -1
  5. package/components/scrollbar/scroll-ref.directive.d.ts +2 -0
  6. package/components/scrollbar/scrollbar.component.d.ts +1 -2
  7. package/fesm2022/taiga-ui-core-classes.mjs +23 -7
  8. package/fesm2022/taiga-ui-core-classes.mjs.map +1 -1
  9. package/fesm2022/taiga-ui-core-components-button.mjs +2 -2
  10. package/fesm2022/taiga-ui-core-components-button.mjs.map +1 -1
  11. package/fesm2022/taiga-ui-core-components-calendar.mjs +1 -1
  12. package/fesm2022/taiga-ui-core-components-calendar.mjs.map +1 -1
  13. package/fesm2022/taiga-ui-core-components-carousel.mjs +2 -2
  14. package/fesm2022/taiga-ui-core-components-carousel.mjs.map +1 -1
  15. package/fesm2022/taiga-ui-core-components-cell.mjs +6 -9
  16. package/fesm2022/taiga-ui-core-components-cell.mjs.map +1 -1
  17. package/fesm2022/taiga-ui-core-components-checkbox.mjs +2 -2
  18. package/fesm2022/taiga-ui-core-components-checkbox.mjs.map +1 -1
  19. package/fesm2022/taiga-ui-core-components-data-list.mjs +7 -7
  20. package/fesm2022/taiga-ui-core-components-data-list.mjs.map +1 -1
  21. package/fesm2022/taiga-ui-core-components-icon.mjs +2 -2
  22. package/fesm2022/taiga-ui-core-components-icon.mjs.map +1 -1
  23. package/fesm2022/taiga-ui-core-components-label.mjs +3 -3
  24. package/fesm2022/taiga-ui-core-components-label.mjs.map +1 -1
  25. package/fesm2022/taiga-ui-core-components-link.mjs +2 -2
  26. package/fesm2022/taiga-ui-core-components-link.mjs.map +1 -1
  27. package/fesm2022/taiga-ui-core-components-notification.mjs +2 -2
  28. package/fesm2022/taiga-ui-core-components-notification.mjs.map +1 -1
  29. package/fesm2022/taiga-ui-core-components-radio.mjs +2 -2
  30. package/fesm2022/taiga-ui-core-components-radio.mjs.map +1 -1
  31. package/fesm2022/taiga-ui-core-components-root.mjs +3 -3
  32. package/fesm2022/taiga-ui-core-components-root.mjs.map +1 -1
  33. package/fesm2022/taiga-ui-core-components-scrollbar.mjs +34 -49
  34. package/fesm2022/taiga-ui-core-components-scrollbar.mjs.map +1 -1
  35. package/fesm2022/taiga-ui-core-components-textfield.mjs +6 -5
  36. package/fesm2022/taiga-ui-core-components-textfield.mjs.map +1 -1
  37. package/fesm2022/taiga-ui-core-components-title.mjs +3 -3
  38. package/fesm2022/taiga-ui-core-components-title.mjs.map +1 -1
  39. package/fesm2022/taiga-ui-core-directives-appearance.mjs +3 -3
  40. package/fesm2022/taiga-ui-core-directives-appearance.mjs.map +1 -1
  41. package/fesm2022/taiga-ui-core-directives-group.mjs +3 -3
  42. package/fesm2022/taiga-ui-core-directives-group.mjs.map +1 -1
  43. package/fesm2022/taiga-ui-core-directives-icons.mjs +3 -3
  44. package/fesm2022/taiga-ui-core-directives-icons.mjs.map +1 -1
  45. package/fesm2022/taiga-ui-core-portals-alert.mjs +3 -3
  46. package/fesm2022/taiga-ui-core-portals-alert.mjs.map +1 -1
  47. package/fesm2022/taiga-ui-core-portals-dialog.mjs +2 -2
  48. package/fesm2022/taiga-ui-core-portals-dialog.mjs.map +1 -1
  49. package/fesm2022/taiga-ui-core-portals-dropdown.mjs +154 -140
  50. package/fesm2022/taiga-ui-core-portals-dropdown.mjs.map +1 -1
  51. package/fesm2022/taiga-ui-core-portals-hint.mjs +32 -34
  52. package/fesm2022/taiga-ui-core-portals-hint.mjs.map +1 -1
  53. package/fesm2022/taiga-ui-core-portals-modal.mjs +3 -3
  54. package/fesm2022/taiga-ui-core-portals-modal.mjs.map +1 -1
  55. package/fesm2022/taiga-ui-core-tokens.mjs +31 -9
  56. package/fesm2022/taiga-ui-core-tokens.mjs.map +1 -1
  57. package/fesm2022/taiga-ui-core-utils-dom.mjs +21 -1
  58. package/fesm2022/taiga-ui-core-utils-dom.mjs.map +1 -1
  59. package/package.json +4 -4
  60. package/portals/dropdown/dropdown-anchor.directive.d.ts +5 -1
  61. package/portals/dropdown/dropdown-anchored.directive.d.ts +1 -1
  62. package/portals/dropdown/dropdown-context.directive.d.ts +3 -4
  63. package/portals/dropdown/dropdown-selection.directive.d.ts +1 -1
  64. package/portals/dropdown/dropdown.component.d.ts +3 -4
  65. package/portals/dropdown/dropdown.directive.d.ts +1 -0
  66. package/portals/dropdown/dropdown.providers.d.ts +1 -1
  67. package/portals/hint/hint-anchor.directive.d.ts +5 -1
  68. package/portals/hint/hint-pointer.directive.d.ts +1 -3
  69. package/portals/hint/hint.d.ts +1 -2
  70. package/tokens/date-format.d.ts +19 -0
  71. package/tokens/number-format.d.ts +18 -8
  72. package/utils/dom/anchor-delegate.d.ts +1 -0
  73. package/utils/dom/index.d.ts +1 -0
@@ -1,20 +1,20 @@
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, ElementRef, INJECTOR, ChangeDetectorRef, signal, TemplateRef, contentChild, model, PLATFORM_ID, ViewContainerRef, afterNextRender } 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 } 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
- import { tuiCheckFixedPosition, tuiGetWordRange } from '@taiga-ui/core/utils/dom';
10
+ import { tuiCheckFixedPosition, tuiAnchorDelegate, 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';
16
16
  import { TuiAnimated } from '@taiga-ui/cdk/directives/animated';
17
- import { TuiScrollbar } from '@taiga-ui/core/components/scrollbar';
17
+ import { TuiScrollbar, TuiScrollControls, TUI_SCROLL_REF } from '@taiga-ui/core/components/scrollbar';
18
18
  import { TUI_VIEWPORT, TUI_DARK_MODE, TUI_SELECTION_STREAM } from '@taiga-ui/core/tokens';
19
19
  import { EMPTY_CLIENT_RECT, TUI_TRUE_HANDLER, CHAR_ZERO_WIDTH_SPACE, CHAR_NO_BREAK_SPACE } from '@taiga-ui/cdk/constants';
20
20
  import { tuiClamp } from '@taiga-ui/cdk/utils/math';
@@ -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
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.rect = inject(TuiRectAccessor);
180
108
  this.viewport = inject(TUI_VIEWPORT);
181
109
  this.vvs = inject(TuiVisualViewportService);
182
110
  this.options = inject(TUI_DROPDOWN_OPTIONS);
@@ -194,7 +122,7 @@ class TuiDropdownAnchored {
194
122
  const { maxHeight, minHeight, offset, limitWidth } = this.options;
195
123
  const parent = this.el.offsetParent?.getBoundingClientRect() || EMPTY_CLIENT_RECT;
196
124
  const { left = 0, top = 0 } = this.position === 'fixed' ? {} : parent;
197
- const rect = this.accessor.getClientRect();
125
+ const rect = this.rect.getClientRect();
198
126
  const viewport = this.viewport.getClientRect();
199
127
  const zoom = this.directive.el.currentCSSZoom || 1;
200
128
  const above = rect.top - viewport.top - 2 * offset;
@@ -218,8 +146,8 @@ class TuiDropdownAnchored {
218
146
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchored, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
219
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
153
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchored, decorators: [{
@@ -227,19 +155,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
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
  }] });
235
163
 
236
164
  /**
237
- * @description:
238
- * This component is used to show template in a portal
239
- * using default style of white rounded box with a shadow
165
+ * TODO: Remove extends TuiScrollbar in v6 when TuiScrollable is dropped
240
166
  */
241
- class TuiDropdownComponent {
167
+ class TuiDropdownComponent extends TuiScrollbar {
242
168
  constructor() {
169
+ super(...arguments);
243
170
  this.options = inject(TUI_DROPDOWN_OPTIONS);
244
171
  this.directive = inject(TuiDropdownDirective);
245
172
  this.context = inject(TUI_DROPDOWN_CONTEXT, { optional: true });
@@ -247,15 +174,48 @@ class TuiDropdownComponent {
247
174
  this.theme = computed((_ = this.darkMode()) => this.directive.el.closest('[tuiTheme]')?.getAttribute('tuiTheme'));
248
175
  this.close = () => this.directive.toggle(false);
249
176
  }
250
- 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: 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 }); }
177
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
178
+ 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()", "style.max-block-size.px": "options.maxHeight" } }, providers: [
179
+ {
180
+ provide: TUI_SCROLL_REF,
181
+ useFactory: () => inject(TuiDropdownComponent).browserScrollRef,
182
+ },
183
+ ], usesInheritance: true, hostDirectives: [{ directive: i1.TuiActiveZone }, { directive: i2.TuiAnimated }, { directive: TuiDropdownAnchored }], ngImport: i0, template: `
184
+ <tui-scroll-controls class="t-scrollbar" />
185
+ <div class="t-wrapper">
186
+ <div
187
+ *polymorpheusOutlet="
188
+ directive.content() as text;
189
+ context: {$implicit: close}
190
+ "
191
+ [innerHTML]="text"
192
+ ></div>
193
+ </div>
194
+ `, isInline: true, 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:auto;isolation:isolate;pointer-events:auto;outline-offset:-1px;outline:1px solid color-mix(in srgb,rgb(from var(--tui-border-normal) r g b / 1) 12%,var(--tui-background-elevation-1));overscroll-behavior:none;position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline;--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}:host._delegated{scroll-timeline:none}.t-wrapper{z-index:-1;flex:1}.t-wrapper>*{padding:1rem}@supports (anchor-name: --t-scrollbar){.t-scrollbar{position:fixed;inset:anchor(top) anchor(right) anchor(bottom) anchor(left);position-anchor:--t-scrollbar;min-inline-size:0;min-block-size:0;margin:0}}\n"], dependencies: [{ kind: "directive", type: PolymorpheusOutlet, selector: "[polymorpheusOutlet]", inputs: ["polymorpheusOutlet", "polymorpheusOutletContext"] }, { kind: "component", type: TuiScrollControls, selector: "tui-scroll-controls" }], changeDetection: i0.ChangeDetectionStrategy.Default }); }
252
195
  }
253
196
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownComponent, decorators: [{
254
197
  type: Component,
255
- args: [{ selector: 'tui-dropdown', imports: [PolymorpheusOutlet, TuiScrollbar], changeDetection: ChangeDetectionStrategy.Default, hostDirectives: [TuiActiveZone, TuiAnimated, TuiDropdownAnchored], host: {
198
+ args: [{ selector: 'tui-dropdown', imports: [PolymorpheusOutlet, TuiScrollControls], template: `
199
+ <tui-scroll-controls class="t-scrollbar" />
200
+ <div class="t-wrapper">
201
+ <div
202
+ *polymorpheusOutlet="
203
+ directive.content() as text;
204
+ context: {$implicit: close}
205
+ "
206
+ [innerHTML]="text"
207
+ ></div>
208
+ </div>
209
+ `, changeDetection: ChangeDetectionStrategy.Default, providers: [
210
+ {
211
+ provide: TUI_SCROLL_REF,
212
+ useFactory: () => inject(TuiDropdownComponent).browserScrollRef,
213
+ },
214
+ ], hostDirectives: [TuiActiveZone, TuiAnimated, TuiDropdownAnchored], host: {
256
215
  '[attr.data-appearance]': 'options.appearance',
257
216
  '[attr.tuiTheme]': 'theme()',
258
- }, 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"] }]
217
+ '[style.max-block-size.px]': 'options.maxHeight',
218
+ }, 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:auto;isolation:isolate;pointer-events:auto;outline-offset:-1px;outline:1px solid color-mix(in srgb,rgb(from var(--tui-border-normal) r g b / 1) 12%,var(--tui-background-elevation-1));overscroll-behavior:none;position-try-fallbacks:flip-block,flip-inline,flip-block flip-inline;--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}:host._delegated{scroll-timeline:none}.t-wrapper{z-index:-1;flex:1}.t-wrapper>*{padding:1rem}@supports (anchor-name: --t-scrollbar){.t-scrollbar{position:fixed;inset:anchor(top) anchor(right) anchor(bottom) anchor(left);position-anchor:--t-scrollbar;min-inline-size:0;min-block-size:0;margin:0}}\n"] }]
259
219
  }] });
260
220
 
261
221
  /**
@@ -297,20 +257,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
297
257
  args: [{ selector: '[tuiDropdownA11y]' }]
298
258
  }] });
299
259
 
300
- class TuiDropdownAnchor {
260
+ class TuiDropdownAnchor extends TuiRectAccessor {
301
261
  constructor() {
262
+ super(...arguments);
263
+ this.el = tuiInjectElement();
302
264
  this.anchor = `--${tuiGenerateId()}`;
265
+ this.type = 'dropdown';
266
+ }
267
+ getClientRect() {
268
+ return this.el.getBoundingClientRect();
303
269
  }
304
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
270
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
305
271
  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: [
272
+ tuiAsRectAccessor(TuiDropdownAnchor),
306
273
  tuiProvide(TUI_DROPDOWN_HOST, ElementRef),
307
274
  tuiProvide(TUI_DROPDOWN_ANCHOR, ElementRef),
308
- ], ngImport: i0 }); }
275
+ ], usesInheritance: true, ngImport: i0 }); }
309
276
  }
310
277
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownAnchor, decorators: [{
311
278
  type: Directive,
312
279
  args: [{
313
280
  providers: [
281
+ tuiAsRectAccessor(TuiDropdownAnchor),
314
282
  tuiProvide(TUI_DROPDOWN_HOST, ElementRef),
315
283
  tuiProvide(TUI_DROPDOWN_ANCHOR, ElementRef),
316
284
  ],
@@ -321,6 +289,79 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
321
289
  }]
322
290
  }] });
323
291
 
292
+ class TuiDropdownPosition extends TuiPositionAccessor {
293
+ constructor() {
294
+ super(...arguments);
295
+ this.el = tuiInjectElement();
296
+ this.options = inject(TUI_DROPDOWN_OPTIONS);
297
+ this.viewport = inject(TUI_VIEWPORT);
298
+ this.direction = new Subject();
299
+ this.type = 'dropdown';
300
+ this.accessor = tuiInjectAccessor(TuiRectAccessor, 'dropdown');
301
+ this.tuiDropdownDirectionChange = outputFromObservable(this.direction.pipe(distinctUntilChanged()));
302
+ }
303
+ getPosition({ width, height }) {
304
+ if (!width && !height) {
305
+ this.previous = undefined;
306
+ }
307
+ const hostRect = this.accessor.getClientRect();
308
+ const viewportRect = this.viewport.getClientRect();
309
+ const { minHeight, direction, offset, limitWidth } = this.options;
310
+ const align = this.getAlign(this.options.align);
311
+ const previous = this.previous || direction || 'bottom';
312
+ const viewport = {
313
+ top: viewportRect.top - offset,
314
+ bottom: viewportRect.bottom + offset,
315
+ right: viewportRect.right - offset,
316
+ left: viewportRect.left + offset,
317
+ };
318
+ const available = {
319
+ top: hostRect.top - 2 * offset - viewport.top,
320
+ bottom: viewport.bottom - hostRect.bottom - 2 * offset,
321
+ };
322
+ const rectWidth = limitWidth === 'fixed' ? hostRect.width : width;
323
+ const right = Math.max(hostRect.right - rectWidth, offset);
324
+ const left = hostRect.left + width < viewport.right ? hostRect.left : right;
325
+ const better = available.top > available.bottom ? 'top' : 'bottom';
326
+ const position = {
327
+ top: hostRect.top - offset - height,
328
+ bottom: hostRect.bottom + offset,
329
+ right: Math.max(viewport.left, right),
330
+ center: hostRect.left + hostRect.width / 2 + width / 2 < viewport.right
331
+ ? hostRect.left + hostRect.width / 2 - width / 2
332
+ : right,
333
+ left: Math.max(viewport.left, left),
334
+ };
335
+ if ((available[previous] > minHeight && direction) ||
336
+ available[previous] > height) {
337
+ this.direction.next(previous);
338
+ return [position[align], position[previous]];
339
+ }
340
+ this.previous = better;
341
+ this.direction.next(better);
342
+ return [position[align], position[better]];
343
+ }
344
+ getAlign(align) {
345
+ const rtl = this.el.matches('[dir="rtl"] :scope');
346
+ if (rtl && align === 'start') {
347
+ return 'right';
348
+ }
349
+ if (rtl && align === 'end') {
350
+ return 'left';
351
+ }
352
+ if (align === 'center') {
353
+ return 'center';
354
+ }
355
+ return align === 'end' ? 'right' : 'left';
356
+ }
357
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPosition, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
358
+ 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 }); }
359
+ }
360
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPosition, decorators: [{
361
+ type: Directive,
362
+ args: [{ providers: [tuiAsPositionAccessor(TuiDropdownPosition)] }]
363
+ }] });
364
+
324
365
  class TuiDropdownDirective {
325
366
  constructor() {
326
367
  this.injector = inject(INJECTOR);
@@ -350,11 +391,12 @@ class TuiDropdownDirective {
350
391
  : content,
351
392
  });
352
393
  }
394
+ /** @deprecated remove in v6 */
353
395
  get accessor() {
354
396
  const accessors = this.injector.get(TuiRectAccessor, null, {
355
397
  self: true,
356
398
  });
357
- return tuiFallbackAccessor('dropdown')(accessors, this);
399
+ return ([...(accessors || [])].reverse().find(({ type }) => type === 'dropdown') || this);
358
400
  }
359
401
  get position() {
360
402
  return tuiCheckFixedPosition(this.el) ? 'fixed' : 'absolute';
@@ -394,10 +436,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
394
436
  TuiDropdownAnchor,
395
437
  TuiDropdownDriverDirective,
396
438
  { directive: TuiDropdownA11y, inputs: ['tuiDropdownRole'] },
397
- {
398
- directive: TuiDropdownPosition,
399
- outputs: ['tuiDropdownDirectionChange'],
400
- },
439
+ { directive: TuiDropdownPosition, outputs: ['tuiDropdownDirectionChange'] },
401
440
  ],
402
441
  host: { '[class.tui-dropdown-open]': 'ref()' },
403
442
  }]
@@ -578,12 +617,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
578
617
  args: [{ selector: 'ng-template[tuiDropdown]' }]
579
618
  }], ctorParameters: () => [] });
580
619
 
581
- const STYLE = {
582
- position: 'fixed',
583
- blockSize: '1px',
584
- inlineSize: '1px',
585
- pointerEvents: 'none',
586
- };
587
620
  class TuiDropdownContext extends TuiRectAccessor {
588
621
  constructor() {
589
622
  super(...arguments);
@@ -606,14 +639,7 @@ class TuiDropdownContext extends TuiRectAccessor {
606
639
  this.currentRect = EMPTY_CLIENT_RECT;
607
640
  });
608
641
  this.type = 'dropdown';
609
- this.nativeElement = this.doc.createElement('div');
610
- }
611
- ngAfterViewInit() {
612
- const anchorName = `--${tuiGenerateId()}`;
613
- const positionAnchor = this.el.getAttribute('data-tui-anchor');
614
- const style = { ...STYLE, positionAnchor, anchorName };
615
- Object.assign(this.nativeElement.style, style);
616
- this.nativeElement.setAttribute('data-tui-anchor', anchorName);
642
+ this.nativeElement = tuiAnchorDelegate({ width: '1px', height: '1px' });
617
643
  }
618
644
  ngOnDestroy() {
619
645
  this.nativeElement.parentNode?.removeChild(this.nativeElement);
@@ -626,7 +652,6 @@ class TuiDropdownContext extends TuiRectAccessor {
626
652
  this.currentRect = tuiPointToClientRect(x, y);
627
653
  this.nativeElement.style.top = `calc(anchor(top) + ${y - top}px)`;
628
654
  this.nativeElement.style.left = `calc(anchor(left) + ${x - left}px)`;
629
- this.doc.body.appendChild(this.nativeElement);
630
655
  this.driver.next(true);
631
656
  }
632
657
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownContext, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
@@ -770,21 +795,21 @@ class TuiDropdownPositionSided extends TuiPositionAccessor {
770
795
  super(...arguments);
771
796
  this.options = inject(TUI_DROPDOWN_OPTIONS);
772
797
  this.viewport = inject(TUI_VIEWPORT);
773
- this.vertical = inject(TuiDropdownPosition);
798
+ this.vertical = inject(TuiDropdownPosition, { optional: true });
774
799
  this.previous = this.options.direction || 'bottom';
775
800
  this.tuiDropdownSided = input('');
776
801
  this.tuiDropdownSidedOffset = input(4);
777
802
  this.type = 'dropdown';
778
803
  }
779
804
  getPosition(rect) {
780
- if (this.tuiDropdownSided() === false) {
805
+ if (this.tuiDropdownSided() === false && this.vertical) {
781
806
  return this.vertical.getPosition(rect);
782
807
  }
783
808
  const { height, width } = rect;
784
- const hostRect = this.vertical.accessor?.getClientRect() ?? EMPTY_CLIENT_RECT;
809
+ const hostRect = this.vertical?.accessor.getClientRect() ?? EMPTY_CLIENT_RECT;
785
810
  const viewport = this.viewport.getClientRect();
786
811
  const { direction, offset } = this.options;
787
- const adjusted = this.vertical.getAlign(this.options.align);
812
+ const adjusted = this.vertical?.getAlign(this.options.align) || 'center';
788
813
  const align = adjusted === 'center' ? 'left' : adjusted;
789
814
  const available = {
790
815
  top: hostRect.bottom - viewport.top,
@@ -803,21 +828,21 @@ class TuiDropdownPositionSided extends TuiPositionAccessor {
803
828
  const left = available[align] > width ? position[align] : maxLeft;
804
829
  if ((available[this.previous] > height && direction) ||
805
830
  this.previous === better) {
806
- this.vertical.direction.next(this.previous);
831
+ this.vertical?.direction.next(this.previous);
807
832
  return [left, position[this.previous]];
808
833
  }
809
834
  this.previous = better;
810
- this.vertical.direction.next(better);
835
+ this.vertical?.direction.next(better);
811
836
  return [left, position[better]];
812
837
  }
813
838
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPositionSided, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
814
- 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 }); }
839
+ 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 }); }
815
840
  }
816
841
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImport: i0, type: TuiDropdownPositionSided, decorators: [{
817
842
  type: Directive,
818
843
  args: [{
819
844
  selector: '[tuiDropdownSided]',
820
- providers: [TuiDropdownPosition, tuiAsPositionAccessor(TuiDropdownPositionSided)],
845
+ providers: [tuiAsPositionAccessor(TuiDropdownPositionSided)],
821
846
  }]
822
847
  }] });
823
848
 
@@ -847,27 +872,17 @@ class TuiDropdownSelection extends TuiDriver {
847
872
  const visible = valid || this.inDropdown(range);
848
873
  const focus = tuiGetFocused(this.doc);
849
874
  const textfield = focus && tuiIsTextfield(focus) && this.el.contains(focus);
875
+ const show = visible && textfield ? this.isCaretVisible(this.range) : visible;
850
876
  this.updateAnchor();
851
- return visible && textfield ? this.isCaretVisible(this.range) : visible;
877
+ return show;
852
878
  }));
853
879
  this.range = isPlatformBrowser(inject(PLATFORM_ID))
854
880
  ? new Range()
855
881
  : {};
856
882
  this.type = 'dropdown';
857
- this.nativeElement = this.doc.createElement('div');
883
+ this.nativeElement = tuiAnchorDelegate();
858
884
  this.tuiDropdownSelection = input('');
859
885
  this.tuiDropdownSelectionPosition = input('selection');
860
- afterNextRender(() => {
861
- const anchorName = `--${tuiGenerateId()}`;
862
- Object.assign(this.nativeElement.style, {
863
- position: 'fixed',
864
- pointerEvents: 'none',
865
- positionAnchor: this.el.dataset.tuiAnchor,
866
- anchorName,
867
- });
868
- this.nativeElement.dataset.tuiAnchor = anchorName;
869
- this.doc.body.appendChild(this.nativeElement);
870
- });
871
886
  }
872
887
  ngOnDestroy() {
873
888
  this.nativeElement.parentNode?.removeChild(this.nativeElement);
@@ -929,12 +944,11 @@ class TuiDropdownSelection extends TuiDriver {
929
944
  }
930
945
  veryVerySadInputFix(element) {
931
946
  const { ghost = this.initGhost(this.ghostHost) } = this;
932
- const { top, left, width, height } = this.ghostHost.getBoundingClientRect();
947
+ const { width, height } = this.ghostHost.getBoundingClientRect();
933
948
  const { selectionStart, selectionEnd, value } = element;
934
949
  const range = this.doc.createRange();
935
- const hostRect = this.ghostHost.getBoundingClientRect();
936
- ghost.style.top = tuiPx(top - hostRect.top);
937
- ghost.style.left = tuiPx(left - hostRect.left);
950
+ ghost.style.top = '0px';
951
+ ghost.style.left = '0px';
938
952
  ghost.style.width = tuiPx(width);
939
953
  ghost.style.height = tuiPx(height);
940
954
  ghost.textContent = `${CHAR_ZERO_WIDTH_SPACE}${value}${CHAR_NO_BREAK_SPACE}`;