ng-hub-ui-utils 22.12.1 → 22.14.0

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.
package/README.md CHANGED
@@ -384,13 +384,14 @@ export class ExampleComponent {}
384
384
  Inputs: `hubTooltip` (text), `hubTooltipPlacement` (`top` | `bottom` | `left` | `right`,
385
385
  default `top`), `hubTooltipDelay` (fade ms, default `150`), `hubTooltipOffset` (px, default `8`).
386
386
 
387
- > **`TooltipDirective` (`[tooltip]`) is deprecated since 22.9.0.** It still works,
388
- > unchanged — both directives are thin shells over the same `HubTooltipController` — but its
389
- > bare input names (`tooltip`, `placement`, `delay`, `offset`) belong to every directive on
390
- > the element that declares them, which is how it collided with `[hubDropdown]`'s own
391
- > `placement` and with the `tooltip` input of `<hub-badge>`. Migration is attribute for
387
+ > **`TooltipDirective` (`[tooltip]`) was removed in 22.14.0**, having been deprecated since
388
+ > 22.9.0. Its bare input names (`tooltip`, `placement`, `delay`, `offset`) belonged to every
389
+ > directive on the element that declared them, which is how it collided with `[hubDropdown]`'s
390
+ > own `placement` and with the `tooltip` input of `<hub-badge>`. Migration is attribute for
392
391
  > attribute: `tooltip` → `hubTooltip`, `placement` → `hubTooltipPlacement`,
393
- > `delay` → `hubTooltipDelay`, `offset` → `hubTooltipOffset`.
392
+ > `delay` → `hubTooltipDelay`, `offset` → `hubTooltipOffset`. A template left writing
393
+ > `tooltip="…"` still compiles and shows nothing at all, so check the markup as well as the
394
+ > imports.
394
395
 
395
396
  Show the label **only while the host is truncated** with `HubOverflowTooltipDirective`
396
397
  (`[hubOverflowTooltip]`), which tracks truncation live with a `ResizeObserver` and a
@@ -400,6 +401,22 @@ Show the label **only while the host is truncated** with `HubOverflowTooltipDire
400
401
  <span class="label" [hubOverflowTooltip]="item.label">{{ item.label }}</span>
401
402
  ```
402
403
 
404
+ The element that is **hovered** and the element that is **measured** need not be the same.
405
+ By default they are, but a control whose text is clipped by a box inside it wants them apart:
406
+ the hover area is the whole control, while the only box that can report truncation is the
407
+ inner one — a child that clips its own text never lets the overflow reach its parent, so
408
+ measuring the parent reports none and the tooltip goes quiet. Point
409
+ `hubOverflowTooltipMeasure` at the inner box with a CSS selector, resolved inside the host:
410
+
411
+ ```html
412
+ <div class="chip" [hubOverflowTooltip]="item.label" hubOverflowTooltipMeasure=".chip__title">
413
+ <span class="chip__icon"></span>
414
+ <span class="chip__title">{{ item.label }}</span>
415
+ </div>
416
+ ```
417
+
418
+ Unset — or pointing at nothing — the host measures itself, exactly as before.
419
+
403
420
  Theme it from any scope with `--hub-tooltip-*` variables:
404
421
 
405
422
  ```css
@@ -710,8 +727,7 @@ library, because their selectors and data models differ.
710
727
  ### Directives
711
728
 
712
729
  - `HubTooltipDirective` (`[hubTooltip]`) - Tooltip on hover/focus. Inputs: `hubTooltip`, `hubTooltipPlacement`, `hubTooltipDelay`, `hubTooltipOffset`
713
- - `HubOverflowTooltipDirective` (`[hubOverflowTooltip]`) - Tooltip shown only while the host label is truncated. Inputs: `hubOverflowTooltip`, `placement`
714
- - `TooltipDirective` (`[tooltip]`) - **Deprecated since 22.9.0**, kept working. Inputs: `tooltip`, `placement`, `delay`, `offset`
730
+ - `HubOverflowTooltipDirective` (`[hubOverflowTooltip]`) - Tooltip shown only while the label is truncated. Inputs: `hubOverflowTooltip`, `placement`, `hubOverflowTooltipMeasure` (CSS selector, resolved inside the host, naming the box whose truncation decides it; defaults to the host)
715
731
  - `provideHubTooltip(adapter: HubTooltipAdapter)` and `HUB_TOOLTIP_ADAPTER` - Swap the implementation behind `[hubOverflowTooltip]`, app-wide or per subtree; defaults to `hubTooltipAdapter`
716
732
 
717
733
  ### Pipes
@@ -788,6 +804,8 @@ class OverlayRef {
788
804
  }
789
805
 
790
806
  class OverlayPosition {
807
+ // The element the panel is anchored to. The overlay watches it and follows it when it moves.
808
+ readonly origin: HTMLElement | null;
791
809
  flexibleConnectedTo(origin: ElementRef | HTMLElement): this;
792
810
  withPositions(positions: ConnectionPosition[]): this;
793
811
  // `start` / `end` are logical and read from the origin element; this overrides that.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { signal, computed, Injectable, effect, InjectionToken, inject, makeEnvironmentProviders, provideAppInitializer, DestroyRef, ElementRef, TemplateRef, createComponent, ApplicationRef, Pipe, ChangeDetectorRef, Injector, ViewContainerRef, NgZone, input, Directive, afterNextRender } from '@angular/core';
2
+ import { signal, computed, Injectable, effect, InjectionToken, inject, makeEnvironmentProviders, provideAppInitializer, DestroyRef, ElementRef, TemplateRef, createComponent, NgZone, ApplicationRef, Pipe, ChangeDetectorRef, Injector, ViewContainerRef, input, Directive, afterNextRender } from '@angular/core';
3
3
  import { fromEvent, Observable, Subject, isObservable, EMPTY, of, timer, race } from 'rxjs';
4
4
  import { takeUntil, map, filter, withLatestFrom, endWith, take, mergeMap, tap } from 'rxjs/operators';
5
5
  import { DOCUMENT } from '@angular/common';
@@ -1729,6 +1729,20 @@ class OverlayPosition {
1729
1729
  this._origin = origin;
1730
1730
  return this;
1731
1731
  }
1732
+ /**
1733
+ * The element this overlay is anchored to, resolved to a plain node.
1734
+ *
1735
+ * Exposed because the strategy is the only place that knows what the panel is connected to,
1736
+ * and the overlay has to watch that element to keep up with it when it moves.
1737
+ *
1738
+ * @returns The origin element, or `null` while none has been set.
1739
+ */
1740
+ get origin() {
1741
+ if (!this._origin) {
1742
+ return null;
1743
+ }
1744
+ return this._origin instanceof ElementRef ? this._origin.nativeElement : this._origin;
1745
+ }
1732
1746
  /**
1733
1747
  * Sets the preferred positions for the overlay.
1734
1748
  * The order of the array determines the fallback priority.
@@ -1914,6 +1928,8 @@ class OverlayRef {
1914
1928
  _isAttached = false;
1915
1929
  _repositionHandler;
1916
1930
  _repositionFrame = 0;
1931
+ _originFrame = 0;
1932
+ _originBox = null;
1917
1933
  _keydownCallback;
1918
1934
  _unregisterKeydown;
1919
1935
  _backdropClickCallback;
@@ -2042,8 +2058,79 @@ class OverlayRef {
2042
2058
  };
2043
2059
  window.addEventListener('scroll', this._repositionHandler, { capture: true, passive: true });
2044
2060
  window.addEventListener('resize', this._repositionHandler, { passive: true });
2061
+ this._followOrigin();
2062
+ }
2063
+ /**
2064
+ * Follows the origin while it moves for a reason no event announces.
2065
+ *
2066
+ * Scroll and resize both describe the page moving under an origin that stays put. Neither says
2067
+ * anything about the origin itself moving inside a page nobody scrolled — a sibling collapsing
2068
+ * above it, an image landing, an accordion animating shut — and the panel is then left hanging
2069
+ * where its trigger used to be. Since that collapse is animated, one re-measure when it starts
2070
+ * would only move the panel to a place the trigger is still on its way out of: the trigger has
2071
+ * to be followed for as long as it slides.
2072
+ *
2073
+ * The origin's box is read every frame, but the position is re-applied only when it actually
2074
+ * changed, so an overlay whose trigger sits still never touches the DOM. Scheduled outside
2075
+ * Angular's zone, or a zone-based application would run change detection on every frame an
2076
+ * overlay is open.
2077
+ */
2078
+ _followOrigin() {
2079
+ if (!this._config.positionStrategy || typeof requestAnimationFrame !== 'function') {
2080
+ return;
2081
+ }
2082
+ this._originBox = this._measureOrigin();
2083
+ const track = () => {
2084
+ if (!this._isAttached) {
2085
+ this._originFrame = 0;
2086
+ return;
2087
+ }
2088
+ this._originFrame = requestAnimationFrame(track);
2089
+ // Read again rather than captured once: a consumer is free to re-anchor a live overlay,
2090
+ // and the panel has to end up following whatever it is connected to now.
2091
+ const box = this._measureOrigin();
2092
+ const previous = this._originBox;
2093
+ if (!box) {
2094
+ return;
2095
+ }
2096
+ if (previous &&
2097
+ previous.top === box.top &&
2098
+ previous.left === box.left &&
2099
+ previous.width === box.width &&
2100
+ previous.height === box.height) {
2101
+ return;
2102
+ }
2103
+ this._originBox = box;
2104
+ this.updatePosition();
2105
+ };
2106
+ const start = () => {
2107
+ this._originFrame = requestAnimationFrame(track);
2108
+ };
2109
+ // Resolved through the injector rather than taken in the constructor, so the shape of a
2110
+ // class consumers can instantiate does not change for a private scheduling detail.
2111
+ const zone = this._appRef.injector.get(NgZone, null);
2112
+ if (zone) {
2113
+ zone.runOutsideAngular(start);
2114
+ return;
2115
+ }
2116
+ start();
2117
+ }
2118
+ /**
2119
+ * Reads the origin's box, reduced to the four numbers a move can change.
2120
+ *
2121
+ * @returns The box, or `null` when there is no origin or it has left the document — an element
2122
+ * out of the document reports zeros for everything, and following that would fling the panel
2123
+ * into the corner rather than leave it where it was.
2124
+ */
2125
+ _measureOrigin() {
2126
+ const origin = this._config.positionStrategy?.origin;
2127
+ if (!origin || !origin.isConnected) {
2128
+ return null;
2129
+ }
2130
+ const rect = origin.getBoundingClientRect();
2131
+ return { top: rect.top, left: rect.left, width: rect.width, height: rect.height };
2045
2132
  }
2046
- /** Removes the listeners registered by {@link _listenForReposition}. */
2133
+ /** Releases everything {@link _listenForReposition} started, the origin follow included. */
2047
2134
  _stopListeningForReposition() {
2048
2135
  if (!this._repositionHandler || typeof window === 'undefined') {
2049
2136
  return;
@@ -2055,6 +2142,11 @@ class OverlayRef {
2055
2142
  cancelAnimationFrame(this._repositionFrame);
2056
2143
  this._repositionFrame = 0;
2057
2144
  }
2145
+ if (this._originFrame) {
2146
+ cancelAnimationFrame(this._originFrame);
2147
+ this._originFrame = 0;
2148
+ }
2149
+ this._originBox = null;
2058
2150
  }
2059
2151
  /**
2060
2152
  * Disposes the overlay and cleans up all allocated resources.
@@ -2700,7 +2792,7 @@ let nextTooltipId = 0;
2700
2792
  *
2701
2793
  * Binds hover/focus listeners to a host element and renders a body-portaled,
2702
2794
  * `--hub-tooltip-*`-themeable label on demand. It owns no Angular dependency, so
2703
- * it can be reused both by the `[tooltip]` directive and by other primitives
2795
+ * it can be reused both by the `[hubTooltip]` directive and by other primitives
2704
2796
  * (e.g. a badge overflow tooltip) that want the exact same visual contract
2705
2797
  * without re-implementing the DOM logic.
2706
2798
  *
@@ -3033,65 +3125,6 @@ function provideHubTooltip(adapter) {
3033
3125
  ]);
3034
3126
  }
3035
3127
 
3036
- /**
3037
- * Lightweight tooltip directive.
3038
- *
3039
- * @deprecated Use {@link HubTooltipDirective} (`[hubTooltip]`) instead. The bare
3040
- * attribute and the bare input names `placement`, `delay` and `offset` are not this
3041
- * directive's to hold: Angular feeds one attribute to every directive on the element
3042
- * that declares an input of that name, so `[hubDropdown] placement` fails to compile
3043
- * beside a tooltip, and `[tooltip]` on a `<hub-badge>` — which owns an input of that
3044
- * name — renders two. Kept working, unchanged, until the next major.
3045
- *
3046
- * Apply `[tooltip]` to any element to show a positioned label on hover/focus.
3047
- * The tooltip element is appended to `<body>` so it is never clipped by an
3048
- * overflow container, and every visual aspect is themeable through
3049
- * `--hub-tooltip-*` CSS variables.
3050
- *
3051
- * All DOM work is delegated to {@link HubTooltipController}, so the directive and
3052
- * any imperative consumer (e.g. a badge overflow tooltip) share the exact same
3053
- * behaviour and styling.
3054
- *
3055
- * Styles ship in `styles/tooltip.scss` (mirroring `styles/overlay.scss`). Import
3056
- * it once in your app: `@use 'ng-hub-ui-utils/styles/tooltip';`.
3057
- */
3058
- class TooltipDirective {
3059
- /** Tooltip text content. */
3060
- tooltipTitle = input.required({ ...(ngDevMode ? { debugName: "tooltipTitle" } : /* istanbul ignore next */ {}), alias: 'tooltip' });
3061
- /** Placement of the tooltip relative to the host. */
3062
- placement = input('top', /* @ts-ignore */
3063
- ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
3064
- /** Fade duration in milliseconds, also used as the removal delay on hide. */
3065
- delay = input(150, /* @ts-ignore */
3066
- ...(ngDevMode ? [{ debugName: "delay" }] : /* istanbul ignore next */ []));
3067
- /** Gap in pixels between the host and the tooltip. */
3068
- offset = input(8, /* @ts-ignore */
3069
- ...(ngDevMode ? [{ debugName: "offset" }] : /* istanbul ignore next */ []));
3070
- host = inject(ElementRef);
3071
- controller = new HubTooltipController(this.host.nativeElement);
3072
- constructor() {
3073
- effect(() => {
3074
- this.controller.setOptions({
3075
- placement: this.placement(),
3076
- delay: this.delay(),
3077
- offset: this.offset()
3078
- });
3079
- this.controller.setText(this.tooltipTitle());
3080
- });
3081
- }
3082
- ngOnDestroy() {
3083
- this.controller.destroy();
3084
- }
3085
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3086
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.8", type: TooltipDirective, isStandalone: true, selector: "[tooltip]", inputs: { tooltipTitle: { classPropertyName: "tooltipTitle", publicName: "tooltip", isSignal: true, isRequired: true, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, delay: { classPropertyName: "delay", publicName: "delay", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "offset", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
3087
- }
3088
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: TooltipDirective, decorators: [{
3089
- type: Directive,
3090
- args: [{
3091
- selector: '[tooltip]'
3092
- }]
3093
- }], ctorParameters: () => [], propDecorators: { tooltipTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltip", required: true }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], delay: [{ type: i0.Input, args: [{ isSignal: true, alias: "delay", required: false }] }], offset: [{ type: i0.Input, args: [{ isSignal: true, alias: "offset", required: false }] }] } });
3094
-
3095
3128
  /**
3096
3129
  * Tooltip directive, named the way the rest of the family names itself.
3097
3130
  *
@@ -3100,12 +3133,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
3100
3133
  * container, and every visual aspect is themeable through `--hub-tooltip-*` CSS
3101
3134
  * variables.
3102
3135
  *
3103
- * ## Why this exists beside {@link TooltipDirective}
3136
+ * ## Why every attribute here carries the prefix
3104
3137
  *
3105
- * The older directive claims the bare attribute `[tooltip]` and the bare input names
3106
- * `placement`, `delay` and `offset`. Angular feeds one attribute to **every** directive
3107
- * on the element that declares an input of that name, so those bare names are not this
3108
- * directive's to hold:
3138
+ * This replaced an earlier directive that claimed the bare attribute `[tooltip]` and the
3139
+ * bare input names `placement`, `delay` and `offset`. Angular feeds one attribute to
3140
+ * **every** directive on the element that declares an input of that name, so those bare
3141
+ * names were never a library's to hold:
3109
3142
  *
3110
3143
  * - `[hubDropdown]` declares its own `placement`, typed over eight values where a
3111
3144
  * tooltip understands four. A menu trigger that also wanted a tooltip did not merely
@@ -3165,7 +3198,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
3165
3198
  * Shows a tooltip with the given text **only while the host element is truncated**
3166
3199
  * (its content is wider than its box).
3167
3200
  *
3168
- * Unlike `[tooltip]`, which always shows on hover, this directive is meant for
3201
+ * Unlike `[hubTooltip]`, which always shows on hover, this directive is meant for
3169
3202
  * ellipsised labels: the tooltip appears solely when the text doesn't fit, so it
3170
3203
  * never duplicates already-visible content. Truncation is tracked live with a
3171
3204
  * `ResizeObserver` (host/container resizes) and a `MutationObserver` (text
@@ -3175,13 +3208,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
3175
3208
  * {@link HUB_TOOLTIP_ADAPTER} token, which defaults to the built-in hub-ui
3176
3209
  * tooltip. Swap it app-wide (or per subtree) with `provideHubTooltip(...)`.
3177
3210
  *
3211
+ * The element that is MEASURED and the element that is HOVERED need not be the same. By
3212
+ * default they are — the host does both — but a control whose text is clipped by a box
3213
+ * inside it wants them apart: the hover area is the whole control, while the only box that
3214
+ * can report truncation is the inner one. Point `hubOverflowTooltipMeasure` at that box and
3215
+ * the tooltip covers the control while answering to the text.
3216
+ *
3178
3217
  * Requires the tooltip styles once in your app:
3179
3218
  * `@use 'ng-hub-ui-utils/styles/tooltip';`.
3180
3219
  *
3181
- * @example
3220
+ * @example Host measures itself
3182
3221
  * ```html
3183
3222
  * <span class="label" [hubOverflowTooltip]="item.label">{{ item.label }}</span>
3184
3223
  * ```
3224
+ *
3225
+ * @example Hover the whole chip, measure the title inside it
3226
+ * ```html
3227
+ * <div class="chip" [hubOverflowTooltip]="item.label" hubOverflowTooltipMeasure=".chip__title">
3228
+ * <span class="chip__icon"></span>
3229
+ * <span class="chip__title">{{ item.label }}</span>
3230
+ * </div>
3231
+ * ```
3185
3232
  */
3186
3233
  class HubOverflowTooltipDirective {
3187
3234
  /** Tooltip text; shown only while the host overflows. */
@@ -3189,6 +3236,15 @@ class HubOverflowTooltipDirective {
3189
3236
  /** Placement of the tooltip relative to the host. */
3190
3237
  placement = input('top', /* @ts-ignore */
3191
3238
  ...(ngDevMode ? [{ debugName: "placement" }] : /* istanbul ignore next */ []));
3239
+ /**
3240
+ * CSS selector, resolved inside the host, naming the element whose truncation decides
3241
+ * whether the tooltip speaks. The tooltip still belongs to the host, so the hover area is
3242
+ * unchanged; only the measurement moves.
3243
+ *
3244
+ * Left unset — or pointing at nothing — the host measures itself, which is what this
3245
+ * directive has always done.
3246
+ */
3247
+ measureTarget = input(undefined, { ...(ngDevMode ? { debugName: "measureTarget" } : /* istanbul ignore next */ {}), alias: 'hubOverflowTooltipMeasure' });
3192
3248
  host = inject(ElementRef);
3193
3249
  adapter = inject(HUB_TOOLTIP_ADAPTER);
3194
3250
  handle = null;
@@ -3200,6 +3256,14 @@ class HubOverflowTooltipDirective {
3200
3256
  ...(ngDevMode ? [{ debugName: "ready" }] : /* istanbul ignore next */ []));
3201
3257
  constructor() {
3202
3258
  afterNextRender(() => this.init());
3259
+ // A selector changed after the fact points at a different box, so the observers and
3260
+ // the truncation state both have to be taken again.
3261
+ effect(() => {
3262
+ this.measureTarget();
3263
+ if (this.ready()) {
3264
+ this.observe();
3265
+ }
3266
+ });
3203
3267
  effect(() => {
3204
3268
  if (!this.ready() || !this.handle) {
3205
3269
  return;
@@ -3216,32 +3280,63 @@ class HubOverflowTooltipDirective {
3216
3280
  /** Wires the tooltip handle and the browser-only truncation observers. */
3217
3281
  init() {
3218
3282
  const el = this.host.nativeElement;
3219
- // Attach with no text; the effect feeds the label only while truncated.
3283
+ // The tooltip belongs to the HOST whatever is measured: it is the control the pointer
3284
+ // is over, and the box that reports truncation may be a fraction of it.
3220
3285
  this.handle = this.adapter.attach(el, '', { placement: this.placement() });
3221
- this.measure(el);
3222
3286
  if (typeof ResizeObserver !== 'undefined') {
3223
- this.resizeObserver = new ResizeObserver(() => this.measure(el));
3224
- this.resizeObserver.observe(el);
3287
+ // Re-resolving on every callback rather than closing over the element: content
3288
+ // rendered after this point can bring the measured box with it.
3289
+ this.resizeObserver = new ResizeObserver(() => this.measure());
3225
3290
  }
3226
3291
  if (typeof MutationObserver !== 'undefined') {
3227
- this.mutationObserver = new MutationObserver(() => this.measure(el));
3292
+ // A mutation can replace the measured box, so the observers are re-pointed rather
3293
+ // than merely re-read.
3294
+ this.mutationObserver = new MutationObserver(() => this.observe());
3228
3295
  this.mutationObserver.observe(el, { childList: true, characterData: true, subtree: true });
3229
3296
  }
3297
+ this.observe();
3230
3298
  this.ready.set(true);
3231
3299
  }
3232
- /** Updates the truncation state from the host's layout. */
3233
- measure(el) {
3300
+ /**
3301
+ * Points the resize observer at the boxes that can change the answer — the host, whose
3302
+ * width bounds everything, and the measured box when it is a different element — and
3303
+ * takes the measurement again.
3304
+ */
3305
+ observe() {
3306
+ const host = this.host.nativeElement;
3307
+ const target = this.resolveTarget();
3308
+ if (this.resizeObserver) {
3309
+ this.resizeObserver.disconnect();
3310
+ this.resizeObserver.observe(host);
3311
+ if (target !== host) {
3312
+ this.resizeObserver.observe(target);
3313
+ }
3314
+ }
3315
+ this.measure();
3316
+ }
3317
+ /**
3318
+ * The element whose overflow is the question. Falls back to the host, so a selector that
3319
+ * matches nothing behaves exactly as no selector at all rather than silently going quiet.
3320
+ */
3321
+ resolveTarget() {
3322
+ const host = this.host.nativeElement;
3323
+ const selector = this.measureTarget();
3324
+ return (selector ? host.querySelector(selector) : null) ?? host;
3325
+ }
3326
+ /** Updates the truncation state from the measured box's layout. */
3327
+ measure() {
3328
+ const el = this.resolveTarget();
3234
3329
  this.overflowing.set(el.scrollWidth > el.clientWidth + 1);
3235
3330
  }
3236
3331
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubOverflowTooltipDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
3237
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.8", type: HubOverflowTooltipDirective, isStandalone: true, selector: "[hubOverflowTooltip]", inputs: { text: { classPropertyName: "text", publicName: "hubOverflowTooltip", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
3332
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "22.0.8", type: HubOverflowTooltipDirective, isStandalone: true, selector: "[hubOverflowTooltip]", inputs: { text: { classPropertyName: "text", publicName: "hubOverflowTooltip", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "placement", isSignal: true, isRequired: false, transformFunction: null }, measureTarget: { classPropertyName: "measureTarget", publicName: "hubOverflowTooltipMeasure", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
3238
3333
  }
3239
3334
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImport: i0, type: HubOverflowTooltipDirective, decorators: [{
3240
3335
  type: Directive,
3241
3336
  args: [{
3242
3337
  selector: '[hubOverflowTooltip]'
3243
3338
  }]
3244
- }], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "hubOverflowTooltip", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }] } });
3339
+ }], ctorParameters: () => [], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "hubOverflowTooltip", required: false }] }], placement: [{ type: i0.Input, args: [{ isSignal: true, alias: "placement", required: false }] }], measureTarget: [{ type: i0.Input, args: [{ isSignal: true, alias: "hubOverflowTooltipMeasure", required: false }] }] } });
3245
3340
 
3246
3341
  /*
3247
3342
  * Public API Surface of utils
@@ -3251,5 +3346,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
3251
3346
  * Generated bundle index. Do not edit.
3252
3347
  */
3253
3348
 
3254
- export { ContentRef, FOCUSABLE_ELEMENTS_SELECTOR, GetPipe, HUB_DROPDOWN_POSITIONS, HUB_INK_LIGHTNESS_THRESHOLD, HUB_NAMED_COLORS, HUB_TOOLTIP_ADAPTER, HUB_TRANSLATION_CONFIG, HUB_TRANSLATION_PREFIX, HUB_TRANSLATION_SOURCE, HubDragDropService, HubOverflowTooltipDirective, HubTooltipController, HubTooltipDirective, HubTranslationService, IsObjectPipe, IsObservablePipe, IsStringPipe, OverlayPosition, OverlayRef, OverlayService, PopupService, ScrollBar, TooltipDirective, TranslatePipe, UcfirstPipe, UnwrapAsyncPipe, clamp, clampToSrgbGamut, closest, compositeOver, computeTargetIndex, containsNode, contrastAPCA, contrastRatio, copyArrayItem, createNativeDragImage, createPointerDragSession, debouncedSignal, equals, generateUniqueId, getActiveElement, getFocusableBoundaryElements, getValue, getValueInRange, hubCompleteTransition, hubFocusTrap, hubRunTransition, hubTooltipAdapter, interpolateString, isDefined, isInSrgbGamut, isInteger, isNumber, isObject, isPromise, isString, isValidColor, maxSrgbChroma, mergeDeep, moveItemInArray, oklchToRgb, padNumber, parseColor, provideHubTooltip, provideHubTranslation, provideHubTranslationAdapter, readableOn, reflow, regExpEscape, registerOverlayKeydown, relativeLuminance, removeAccents, resolveDropPosition, resolveHubAccent, rgbToOklch, runInZone, toAbsoluteIndex, toHex, toInteger, toRgb, toString, transferArrayItem };
3349
+ export { ContentRef, FOCUSABLE_ELEMENTS_SELECTOR, GetPipe, HUB_DROPDOWN_POSITIONS, HUB_INK_LIGHTNESS_THRESHOLD, HUB_NAMED_COLORS, HUB_TOOLTIP_ADAPTER, HUB_TRANSLATION_CONFIG, HUB_TRANSLATION_PREFIX, HUB_TRANSLATION_SOURCE, HubDragDropService, HubOverflowTooltipDirective, HubTooltipController, HubTooltipDirective, HubTranslationService, IsObjectPipe, IsObservablePipe, IsStringPipe, OverlayPosition, OverlayRef, OverlayService, PopupService, ScrollBar, TranslatePipe, UcfirstPipe, UnwrapAsyncPipe, clamp, clampToSrgbGamut, closest, compositeOver, computeTargetIndex, containsNode, contrastAPCA, contrastRatio, copyArrayItem, createNativeDragImage, createPointerDragSession, debouncedSignal, equals, generateUniqueId, getActiveElement, getFocusableBoundaryElements, getValue, getValueInRange, hubCompleteTransition, hubFocusTrap, hubRunTransition, hubTooltipAdapter, interpolateString, isDefined, isInSrgbGamut, isInteger, isNumber, isObject, isPromise, isString, isValidColor, maxSrgbChroma, mergeDeep, moveItemInArray, oklchToRgb, padNumber, parseColor, provideHubTooltip, provideHubTranslation, provideHubTranslationAdapter, readableOn, reflow, regExpEscape, registerOverlayKeydown, relativeLuminance, removeAccents, resolveDropPosition, resolveHubAccent, rgbToOklch, runInZone, toAbsoluteIndex, toHex, toInteger, toRgb, toString, transferArrayItem };
3255
3350
  //# sourceMappingURL=ng-hub-ui-utils.mjs.map