@lucca-front/ng 21.1.2 → 21.1.3
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/fesm2022/lucca-front-ng-callout.mjs +2 -2
- package/fesm2022/lucca-front-ng-callout.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-core-select.mjs +5 -2
- package/fesm2022/lucca-front-ng-core-select.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-date2.mjs +2 -2
- package/fesm2022/lucca-front-ng-date2.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-dialog.mjs +1 -1
- package/fesm2022/lucca-front-ng-dialog.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-form-field.mjs +4 -4
- package/fesm2022/lucca-front-ng-form-field.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-forms-phone-number-input.mjs +2 -2
- package/fesm2022/lucca-front-ng-forms-phone-number-input.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-forms-rich-text-input.mjs +163 -64
- package/fesm2022/lucca-front-ng-forms-rich-text-input.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-forms.mjs +14 -14
- package/fesm2022/lucca-front-ng-forms.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-highlight-data.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-multi-select.mjs +20 -10
- package/fesm2022/lucca-front-ng-multi-select.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-resource-card.mjs +2 -2
- package/fesm2022/lucca-front-ng-resource-card.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-simple-select.mjs +5 -4
- package/fesm2022/lucca-front-ng-simple-select.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-skeleton.mjs +4 -4
- package/fesm2022/lucca-front-ng-skeleton.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-toast.mjs +2 -2
- package/fesm2022/lucca-front-ng-toast.mjs.map +1 -1
- package/fesm2022/lucca-front-ng-tooltip.mjs +129 -162
- package/fesm2022/lucca-front-ng-tooltip.mjs.map +1 -1
- package/package.json +14 -14
- package/schematics/lib/component-mapper.js +1 -1
- package/schematics/lib/css-mapper.js +1 -1
- package/schematics/lu-button/index.js +1 -1
- package/schematics/lu-container/index.js +1 -1
- package/schematics/lu-icon/index.js +1 -1
- package/schematics/lu-loading/index.js +1 -1
- package/schematics/lu-select/index.js +1 -1
- package/schematics/lu-text-input/index.js +1 -1
- package/schematics/new-icons/index.js +1 -1
- package/src/components/cdk/_global.scss +8 -8
- package/types/lucca-front-ng-forms-rich-text-input.d.ts +69 -14
- package/types/lucca-front-ng-tooltip.d.ts +9 -17
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { trigger, state, style, transition, animate } from '@angular/animations';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { inject, DestroyRef, signal, ChangeDetectionStrategy, Component, Injectable, ElementRef, Renderer2,
|
|
4
|
-
import { Subject,
|
|
3
|
+
import { inject, DestroyRef, signal, ChangeDetectionStrategy, Component, Injectable, ElementRef, Renderer2, Injector, input, linkedSignal, numberAttribute, booleanAttribute, computed, effect, Directive, NgModule } from '@angular/core';
|
|
4
|
+
import { Subject, switchMap, of, from, timer, startWith } from 'rxjs';
|
|
5
5
|
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
|
|
6
6
|
import { ComponentPortal } from '@angular/cdk/portal';
|
|
7
|
-
import {
|
|
7
|
+
import { toSignal, toObservable, takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
8
8
|
import { isNotNil, ɵeffectWithDeps as _effectWithDeps } from '@lucca-front/ng/core';
|
|
9
|
-
import { debounceTime, filter
|
|
9
|
+
import { debounceTime, filter, debounce, tap, map } from 'rxjs/operators';
|
|
10
10
|
import { DOCUMENT } from '@angular/common';
|
|
11
11
|
|
|
12
12
|
const luTransformTooltip = trigger('transformTooltip', [
|
|
@@ -30,7 +30,6 @@ class LuTooltipPanelComponent {
|
|
|
30
30
|
this.mouseEnter$ = new Subject();
|
|
31
31
|
this.mouseLeave$ = new Subject();
|
|
32
32
|
this.content = signal(null, ...(ngDevMode ? [{ debugName: "content" }] : []));
|
|
33
|
-
this.id = signal(null, ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
34
33
|
this.contentPositionClasses = signal({}, ...(ngDevMode ? [{ debugName: "contentPositionClasses" }] : []));
|
|
35
34
|
}
|
|
36
35
|
setPanelPosition(posX, posY) {
|
|
@@ -42,115 +41,75 @@ class LuTooltipPanelComponent {
|
|
|
42
41
|
});
|
|
43
42
|
}
|
|
44
43
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: LuTooltipPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
45
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: LuTooltipPanelComponent, isStandalone: true, selector: "lu-tooltip-panel", host: { attributes: { "role": "tooltip" }, listeners: { "mouseenter": "mouseEnter$.next()", "mouseleave": "mouseLeave$.next()" }
|
|
44
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: LuTooltipPanelComponent, isStandalone: true, selector: "lu-tooltip-panel", host: { attributes: { "role": "tooltip" }, listeners: { "mouseenter": "mouseEnter$.next()", "mouseleave": "mouseLeave$.next()" } }, ngImport: i0, template: "@if (content(); as content) {\n\t<div class=\"tooltip\" [class]=\"contentPositionClasses()\" [innerHtml]=\"content\"></div>\n}\n", styles: ["@layer components{.tooltip{--components-tooltip-background-color: var(--palettes-neutral-900);--components-tooltip-color: var(--pr-t-color-text-reverse);--components-tooltip-max-width: 15rem;--components-tooltip-transformOrigin: center;--components-tooltip-margin: 0;background-color:var(--components-tooltip-background-color);color:var(--components-tooltip-color);padding-block:var(--pr-t-spacings-50);padding-inline:var(--pr-t-spacings-100);max-inline-size:var(--components-tooltip-max-width);border-radius:var(--pr-t-border-radius-default);font:var(--pr-t-font-body-XS);transform-origin:var(--components-tooltip-transformOrigin);margin:var(--components-tooltip-margin);text-align:center;inline-size:fit-content;animation-name:scaleIn;animation-duration:var(--commons-animations-durations-fast);animation-iteration-count:1;overflow-wrap:break-word}@keyframes scaleIn{0%{transform:scale(0)}to{transform:scale(1)}}.tooltip:empty{display:none}@supports (background-image: -webkit-named-image(i)){@media(hover:hover){[luTooltipWhenEllipsis]:after{content:\"\";display:block}}}}@layer mods{.tooltip.is-above{--components-tooltip-transformOrigin: bottom center}.tooltip.is-below{--components-tooltip-transformOrigin: top center}.tooltip.is-before{--components-tooltip-transformOrigin: center right}.tooltip.is-before.is-above{--components-tooltip-transformOrigin: bottom right}.tooltip.is-before.is-below{--components-tooltip-transformOrigin: top right}.tooltip.is-after{--components-tooltip-transformOrigin: center left}.tooltip.is-after.is-above{--components-tooltip-transformOrigin: bottom left}.tooltip.is-after.is-below{--components-tooltip-transformOrigin: top left}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
46
45
|
}
|
|
47
46
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: LuTooltipPanelComponent, decorators: [{
|
|
48
47
|
type: Component,
|
|
49
48
|
args: [{ selector: 'lu-tooltip-panel', host: {
|
|
50
49
|
role: 'tooltip',
|
|
51
|
-
'[attr.id]': 'id',
|
|
52
50
|
'(mouseenter)': 'mouseEnter$.next()',
|
|
53
51
|
'(mouseleave)': 'mouseLeave$.next()',
|
|
54
52
|
}, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (content(); as content) {\n\t<div class=\"tooltip\" [class]=\"contentPositionClasses()\" [innerHtml]=\"content\"></div>\n}\n", styles: ["@layer components{.tooltip{--components-tooltip-background-color: var(--palettes-neutral-900);--components-tooltip-color: var(--pr-t-color-text-reverse);--components-tooltip-max-width: 15rem;--components-tooltip-transformOrigin: center;--components-tooltip-margin: 0;background-color:var(--components-tooltip-background-color);color:var(--components-tooltip-color);padding-block:var(--pr-t-spacings-50);padding-inline:var(--pr-t-spacings-100);max-inline-size:var(--components-tooltip-max-width);border-radius:var(--pr-t-border-radius-default);font:var(--pr-t-font-body-XS);transform-origin:var(--components-tooltip-transformOrigin);margin:var(--components-tooltip-margin);text-align:center;inline-size:fit-content;animation-name:scaleIn;animation-duration:var(--commons-animations-durations-fast);animation-iteration-count:1;overflow-wrap:break-word}@keyframes scaleIn{0%{transform:scale(0)}to{transform:scale(1)}}.tooltip:empty{display:none}@supports (background-image: -webkit-named-image(i)){@media(hover:hover){[luTooltipWhenEllipsis]:after{content:\"\";display:block}}}}@layer mods{.tooltip.is-above{--components-tooltip-transformOrigin: bottom center}.tooltip.is-below{--components-tooltip-transformOrigin: top center}.tooltip.is-before{--components-tooltip-transformOrigin: center right}.tooltip.is-before.is-above{--components-tooltip-transformOrigin: bottom right}.tooltip.is-before.is-below{--components-tooltip-transformOrigin: top right}.tooltip.is-after{--components-tooltip-transformOrigin: center left}.tooltip.is-after.is-above{--components-tooltip-transformOrigin: bottom left}.tooltip.is-after.is-below{--components-tooltip-transformOrigin: top left}}\n"] }]
|
|
55
53
|
}] });
|
|
56
54
|
|
|
57
55
|
class EllipsisRuler {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
#interval;
|
|
61
|
-
#readPhase;
|
|
62
|
-
#writePhase;
|
|
63
|
-
#document;
|
|
56
|
+
#document = inject(DOCUMENT);
|
|
57
|
+
#parentMasked = this.#document.createElement('div');
|
|
64
58
|
constructor() {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
this.#
|
|
68
|
-
this.#readPhase = this.#interval.pipe(filter((n) => n % 2 === 0));
|
|
69
|
-
this.#writePhase = this.#interval.pipe(filter((n) => n % 2 === 1));
|
|
70
|
-
this.#document = inject(DOCUMENT);
|
|
71
|
-
this.parentMasked = this.#document.createElement('div');
|
|
72
|
-
this.parentMasked.classList.add('pr-u-mask');
|
|
73
|
-
this.parentMasked.setAttribute('aria-hidden', 'true');
|
|
74
|
-
this.#document.body.appendChild(this.parentMasked);
|
|
59
|
+
this.#parentMasked.classList.add('pr-u-mask');
|
|
60
|
+
this.#parentMasked.setAttribute('aria-hidden', 'true');
|
|
61
|
+
this.#document.body.appendChild(this.#parentMasked);
|
|
75
62
|
}
|
|
76
63
|
/**
|
|
77
|
-
*
|
|
78
|
-
* This method checks for ellipsis by cloning the node and checking its width against original element.
|
|
64
|
+
* Checks for ellipsis by cloning the node and comparing its unconstrained width against the original element.
|
|
79
65
|
*
|
|
80
66
|
* We used to do this using scrollWidth but the thing is, it's a rounded value. Sometimes,
|
|
81
67
|
* you'd get true while it should be false and vice-versa, because of rounding.
|
|
82
68
|
*
|
|
83
69
|
* So we duplicate the properties we're interested in on the element to be tested to calculate its ideal size,
|
|
84
70
|
* which we then compare with its current size.
|
|
85
|
-
*
|
|
86
|
-
* To avoid doing multiple reflow per check, we wait for the next microtask on each key step of the process:
|
|
87
|
-
* - After computing element style
|
|
88
|
-
* - After cloning the element and appending it to the DOM
|
|
89
|
-
* - After computing the width of the cloned element
|
|
90
|
-
* - After removing the cloned element from the DOM
|
|
91
|
-
*
|
|
92
|
-
* This way, we have 2 reflows per check, no matter how many elements are checked in a row.
|
|
93
71
|
*/
|
|
94
72
|
async hasEllipsis(element) {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
elementStyle = getComputedStyle(element);
|
|
99
|
-
bodyStyle = getComputedStyle(document.body);
|
|
100
|
-
});
|
|
73
|
+
await this.#nextFrame();
|
|
74
|
+
const elementStyle = getComputedStyle(element);
|
|
75
|
+
const bodyStyle = getComputedStyle(this.#document.body);
|
|
101
76
|
if (elementStyle.textOverflow !== 'ellipsis') {
|
|
102
77
|
return false;
|
|
103
78
|
}
|
|
104
79
|
const { padding, borderWidth, borderStyle, boxSizing, fontFamily, fontWeight, fontStyle } = elementStyle;
|
|
105
80
|
const fontSize = (Number(elementStyle.fontSize.replace('px', '')) / Number(bodyStyle.fontSize.replace('px', ''))).toString() + 'rem';
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
fontSize,
|
|
122
|
-
});
|
|
123
|
-
this.parentMasked.appendChild(elementCloned);
|
|
124
|
-
elementCloned.innerHTML = element.innerHTML;
|
|
81
|
+
await this.#nextFrame();
|
|
82
|
+
const elementCloned = this.#document.createElement('div');
|
|
83
|
+
Object.assign(elementCloned.style, {
|
|
84
|
+
inlineSize: 'fit-content',
|
|
85
|
+
whiteSpace: 'nowrap',
|
|
86
|
+
position: 'absolute',
|
|
87
|
+
visibility: 'hidden',
|
|
88
|
+
padding,
|
|
89
|
+
borderWidth,
|
|
90
|
+
borderStyle,
|
|
91
|
+
boxSizing,
|
|
92
|
+
fontFamily,
|
|
93
|
+
fontWeight,
|
|
94
|
+
fontStyle,
|
|
95
|
+
fontSize,
|
|
125
96
|
});
|
|
126
|
-
|
|
97
|
+
this.#parentMasked.appendChild(elementCloned);
|
|
98
|
+
elementCloned.innerHTML = element.innerHTML;
|
|
127
99
|
try {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
await this.#readOperation(() => {
|
|
131
|
-
clonedElementWidth = elementCloned.getBoundingClientRect().width;
|
|
132
|
-
elementWidth = element.getBoundingClientRect().width;
|
|
133
|
-
});
|
|
100
|
+
const clonedElementWidth = elementCloned.getBoundingClientRect().width;
|
|
101
|
+
const elementWidth = element.getBoundingClientRect().width;
|
|
134
102
|
return clonedElementWidth > elementWidth;
|
|
135
103
|
}
|
|
136
104
|
catch {
|
|
137
105
|
return false;
|
|
138
106
|
}
|
|
139
107
|
finally {
|
|
140
|
-
|
|
141
|
-
this.parentMasked.removeChild(elementCloned);
|
|
142
|
-
});
|
|
108
|
+
this.#parentMasked.removeChild(elementCloned);
|
|
143
109
|
}
|
|
144
110
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
await firstValueFrom(this.#readPhase);
|
|
148
|
-
operation();
|
|
149
|
-
}
|
|
150
|
-
// To avoid multiple reflows, we wait for the next write before inserting/removing the cloned element
|
|
151
|
-
async #writeOperation(operation) {
|
|
152
|
-
await firstValueFrom(this.#writePhase);
|
|
153
|
-
operation();
|
|
111
|
+
#nextFrame() {
|
|
112
|
+
return new Promise((resolve) => requestAnimationFrame(() => resolve()));
|
|
154
113
|
}
|
|
155
114
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: EllipsisRuler, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
156
115
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: EllipsisRuler, providedIn: 'root' }); }
|
|
@@ -166,40 +125,21 @@ class LuTooltipTriggerDirective {
|
|
|
166
125
|
#host;
|
|
167
126
|
#renderer;
|
|
168
127
|
#ruler;
|
|
169
|
-
#zone;
|
|
170
128
|
#injector;
|
|
171
129
|
#destroyRef;
|
|
172
|
-
#
|
|
173
|
-
#
|
|
174
|
-
#hasEllipsis$;
|
|
130
|
+
#isVisible;
|
|
131
|
+
#ellipsisTrigger;
|
|
175
132
|
#hasEllipsis;
|
|
176
133
|
#action;
|
|
177
134
|
#realAction;
|
|
178
|
-
onMouseEnter() {
|
|
179
|
-
this.#action.set('open');
|
|
180
|
-
}
|
|
181
|
-
onMouseLeave() {
|
|
182
|
-
this.#action.set('close');
|
|
183
|
-
}
|
|
184
|
-
onFocus() {
|
|
185
|
-
if (this.#host.nativeElement.getAttribute('aria-expanded') !== 'true') {
|
|
186
|
-
this.#action.set('open');
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
onBlur() {
|
|
190
|
-
this.#action.set('close');
|
|
191
|
-
}
|
|
192
135
|
#effectRef;
|
|
193
|
-
#idEffectRef;
|
|
194
136
|
constructor() {
|
|
195
137
|
this.#overlay = inject(Overlay);
|
|
196
138
|
this.#host = inject(ElementRef);
|
|
197
139
|
this.#renderer = inject(Renderer2);
|
|
198
140
|
this.#ruler = inject(EllipsisRuler);
|
|
199
|
-
this.#zone = inject(NgZone, { optional: true });
|
|
200
141
|
this.#injector = inject(Injector);
|
|
201
142
|
this.#destroyRef = inject(DestroyRef);
|
|
202
|
-
this.#previousTickContent = this.#host.nativeElement.innerText;
|
|
203
143
|
this.luTooltipInput = input('', { ...(ngDevMode ? { debugName: "luTooltipInput" } : {}), alias: 'luTooltip' });
|
|
204
144
|
this.luTooltip = linkedSignal(() => this.luTooltipInput(), ...(ngDevMode ? [{ debugName: "luTooltip" }] : []));
|
|
205
145
|
this.luTooltipEnterDelay = input(300, { ...(ngDevMode ? { debugName: "luTooltipEnterDelay" } : {}), transform: numberAttribute });
|
|
@@ -211,30 +151,20 @@ class LuTooltipTriggerDirective {
|
|
|
211
151
|
this.luTooltipWhenEllipsis = linkedSignal(() => this.luTooltipWhenEllipsisInput(), ...(ngDevMode ? [{ debugName: "luTooltipWhenEllipsis" }] : []));
|
|
212
152
|
this.luTooltipAnchor = input(this.#host, ...(ngDevMode ? [{ debugName: "luTooltipAnchor" }] : []));
|
|
213
153
|
this.id = input(`${this.#host.nativeElement.tagName.toLowerCase()}-tooltip-${nextId++}`, ...(ngDevMode ? [{ debugName: "id" }] : []));
|
|
214
|
-
this.
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
// Resend resize events to trigger the check
|
|
229
|
-
this.resize$.pipe(debounceTime(150)),
|
|
230
|
-
// Include content changes
|
|
231
|
-
this.#innerTextChange$,
|
|
232
|
-
]).pipe(
|
|
233
|
-
// 2. Keep only necessary inputs
|
|
234
|
-
filter$1(([{ whenEllipsis, disabled }]) => !disabled && whenEllipsis),
|
|
235
|
-
// 3. Check for ellipsis
|
|
236
|
-
switchMap(() => this.runOutsideZoneJS(() => this.#ruler.hasEllipsis(this.#host.nativeElement))));
|
|
237
|
-
this.#hasEllipsis = toSignal(this.#hasEllipsis$, { initialValue: false });
|
|
154
|
+
this.ariaDescribedBy = computed(() => {
|
|
155
|
+
if (this.luTooltipDisabled() || this.luTooltipWhenEllipsis() || this.luTooltipOnlyForDisplay()) {
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
return `${this.id()}-panel`;
|
|
159
|
+
}, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
|
|
160
|
+
this.#isVisible = signal(false, ...(ngDevMode ? [{ debugName: "#isVisible" }] : []));
|
|
161
|
+
this.#ellipsisTrigger = signal(0, ...(ngDevMode ? [{ debugName: "#ellipsisTrigger" }] : []));
|
|
162
|
+
this.#hasEllipsis = toSignal(toObservable(this.#ellipsisTrigger).pipe(debounceTime(150), switchMap(() => {
|
|
163
|
+
if (!this.luTooltipWhenEllipsis() || this.luTooltipDisabled()) {
|
|
164
|
+
return of(false);
|
|
165
|
+
}
|
|
166
|
+
return from(this.#ruler.hasEllipsis(this.#host.nativeElement));
|
|
167
|
+
})), { initialValue: false });
|
|
238
168
|
this.#action = signal(null, ...(ngDevMode ? [{ debugName: "#action" }] : []));
|
|
239
169
|
this.#realAction = linkedSignal({ ...(ngDevMode ? { debugName: "#realAction" } : {}), source: this.#action,
|
|
240
170
|
computation: (action, previous) => {
|
|
@@ -244,23 +174,16 @@ class LuTooltipTriggerDirective {
|
|
|
244
174
|
// We only filter open events because even if it's disabled while opened,
|
|
245
175
|
// we want the tooltip to be able to close itself no matter what
|
|
246
176
|
if (this.luTooltipDisabled()) {
|
|
247
|
-
return previous?.value;
|
|
177
|
+
return previous?.value ?? null;
|
|
248
178
|
}
|
|
249
|
-
// If not disabled, let's check for ellipsis if needed
|
|
250
179
|
if (this.luTooltipWhenEllipsis()) {
|
|
251
|
-
return this.#hasEllipsis() ? 'open' : previous
|
|
180
|
+
return this.#hasEllipsis() ? 'open' : (previous?.value ?? null);
|
|
252
181
|
}
|
|
253
|
-
// If it's not disabled and is not triggered based on ellipsis, just return true
|
|
254
182
|
return 'open';
|
|
255
183
|
} });
|
|
256
|
-
|
|
257
|
-
if (this.luTooltipDisabled() || this.luTooltipWhenEllipsis() || this.luTooltipOnlyForDisplay()) {
|
|
258
|
-
return null;
|
|
259
|
-
}
|
|
260
|
-
return `${this.id()}-panel`;
|
|
261
|
-
}, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
|
|
184
|
+
// Action debounce pipeline — kept as Observable since signals can't debounce
|
|
262
185
|
toObservable(this.#realAction)
|
|
263
|
-
.pipe(filter
|
|
186
|
+
.pipe(filter(isNotNil), debounce((action) => timer(action === 'open' ? this.luTooltipEnterDelay() : this.luTooltipLeaveDelay())), tap((event) => {
|
|
264
187
|
if (event === 'open') {
|
|
265
188
|
this.openTooltip();
|
|
266
189
|
}
|
|
@@ -277,27 +200,88 @@ class LuTooltipTriggerDirective {
|
|
|
277
200
|
this.setAccessibilityProperties(null);
|
|
278
201
|
}
|
|
279
202
|
});
|
|
203
|
+
effect((onCleanup) => {
|
|
204
|
+
if (!this.luTooltipWhenEllipsis() || this.luTooltipDisabled()) {
|
|
205
|
+
this.#isVisible.set(false);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
const observer = new IntersectionObserver((entries) => this.#isVisible.set(entries.some((e) => e.isIntersecting)), { rootMargin: '100px' });
|
|
209
|
+
observer.observe(this.#host.nativeElement);
|
|
210
|
+
onCleanup(() => observer.disconnect());
|
|
211
|
+
});
|
|
212
|
+
effect((onCleanup) => {
|
|
213
|
+
if (!this.#isVisible() || !this.luTooltipWhenEllipsis() || this.luTooltipDisabled()) {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const el = this.#host.nativeElement;
|
|
217
|
+
const bump = () => this.#ellipsisTrigger.update((v) => v + 1);
|
|
218
|
+
const resizeObserver = new ResizeObserver(() => bump());
|
|
219
|
+
resizeObserver.observe(el);
|
|
220
|
+
const mutationObserver = new MutationObserver(() => bump());
|
|
221
|
+
mutationObserver.observe(el, { characterData: true, subtree: true, childList: true });
|
|
222
|
+
// Initial check when element becomes visible — prevents regression where tooltips never appear
|
|
223
|
+
bump();
|
|
224
|
+
onCleanup(() => {
|
|
225
|
+
resizeObserver.disconnect();
|
|
226
|
+
mutationObserver.disconnect();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
280
229
|
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
230
|
+
onMouseEnter() {
|
|
231
|
+
this.#action.set('open');
|
|
232
|
+
}
|
|
233
|
+
onMouseLeave() {
|
|
234
|
+
this.#action.set('close');
|
|
235
|
+
}
|
|
236
|
+
onFocus() {
|
|
237
|
+
if (this.#host.nativeElement.getAttribute('aria-expanded') !== 'true') {
|
|
238
|
+
this.#action.set('open');
|
|
285
239
|
}
|
|
286
240
|
}
|
|
241
|
+
onBlur() {
|
|
242
|
+
this.#action.set('close');
|
|
243
|
+
}
|
|
244
|
+
requestOpen() {
|
|
245
|
+
this.#action.set('open');
|
|
246
|
+
}
|
|
247
|
+
requestClose() {
|
|
248
|
+
this.#action.set('close');
|
|
249
|
+
}
|
|
287
250
|
ngOnDestroy() {
|
|
288
251
|
this.closeTooltip();
|
|
252
|
+
if (this.overlayRef) {
|
|
253
|
+
this.overlayRef.dispose();
|
|
254
|
+
delete this.overlayRef;
|
|
255
|
+
}
|
|
289
256
|
}
|
|
290
|
-
|
|
291
|
-
// If tooltip is already opened, don't do anything
|
|
257
|
+
prepareOverlay() {
|
|
292
258
|
if (this.overlayRef) {
|
|
293
259
|
return;
|
|
294
260
|
}
|
|
295
|
-
const position = this.legacyPositionBuilder();
|
|
296
261
|
this.overlayRef = this.#overlay.create({
|
|
297
|
-
positionStrategy: position,
|
|
298
262
|
scrollStrategy: this.#overlay.scrollStrategies.close(),
|
|
299
263
|
disposeOnNavigation: true,
|
|
300
264
|
});
|
|
265
|
+
const describedBy = this.ariaDescribedBy();
|
|
266
|
+
if (describedBy !== null) {
|
|
267
|
+
this.overlayRef.overlayElement.id = describedBy;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
openTooltip() {
|
|
271
|
+
if (this.overlayRef?.hasAttached()) {
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
const position = this.legacyPositionBuilder();
|
|
275
|
+
if (!this.overlayRef) {
|
|
276
|
+
this.overlayRef = this.#overlay.create({
|
|
277
|
+
positionStrategy: position,
|
|
278
|
+
scrollStrategy: this.#overlay.scrollStrategies.close(),
|
|
279
|
+
disposeOnNavigation: true,
|
|
280
|
+
});
|
|
281
|
+
}
|
|
282
|
+
else {
|
|
283
|
+
this.overlayRef.updatePositionStrategy(position);
|
|
284
|
+
}
|
|
301
285
|
const portal = new ComponentPortal(LuTooltipPanelComponent);
|
|
302
286
|
const ref = this.overlayRef.attach(portal);
|
|
303
287
|
position.positionChanges
|
|
@@ -316,27 +300,23 @@ class LuTooltipTriggerDirective {
|
|
|
316
300
|
else {
|
|
317
301
|
ref.instance.content.set('');
|
|
318
302
|
}
|
|
319
|
-
this.#idEffectRef = _effectWithDeps([this.ariaDescribedBy], (ariaDescribedBy) => {
|
|
320
|
-
ref.instance.id.set(ariaDescribedBy);
|
|
321
|
-
}, { injector: this.#injector });
|
|
322
|
-
// On tooltip leave => trigger close
|
|
323
303
|
ref.instance.mouseLeave$.pipe(takeUntilDestroyed(ref.instance.destroyRef)).subscribe(() => this.#action.set('close'));
|
|
324
|
-
// On tooltip enter => trigger open to keep it opened
|
|
325
304
|
ref.instance.mouseEnter$.pipe(takeUntilDestroyed(ref.instance.destroyRef)).subscribe(() => this.#action.set('open'));
|
|
326
305
|
}
|
|
327
306
|
closeTooltip() {
|
|
328
307
|
if (this.overlayRef) {
|
|
329
308
|
this.overlayRef.detach();
|
|
330
|
-
delete this.overlayRef;
|
|
331
309
|
}
|
|
332
310
|
this.#effectRef?.destroy();
|
|
333
|
-
this.#idEffectRef?.destroy();
|
|
334
311
|
}
|
|
335
312
|
setAccessibilityProperties(tabindex) {
|
|
336
313
|
if (tabindex === null) {
|
|
337
314
|
this.#renderer.removeAttribute(this.#host.nativeElement, 'tabindex');
|
|
338
315
|
return;
|
|
339
316
|
}
|
|
317
|
+
if (!this.luTooltipWhenEllipsis() && !this.luTooltipOnlyForDisplay()) {
|
|
318
|
+
this.prepareOverlay();
|
|
319
|
+
}
|
|
340
320
|
const tag = this.#host.nativeElement.tagName.toLowerCase();
|
|
341
321
|
const nativelyFocusableTags = ['a', 'button', 'input', 'select', 'textarea'];
|
|
342
322
|
const isNativelyFocusableTag = nativelyFocusableTags.includes(tag);
|
|
@@ -348,14 +328,7 @@ class LuTooltipTriggerDirective {
|
|
|
348
328
|
this.#renderer.setAttribute(this.#host.nativeElement, 'role', 'button');
|
|
349
329
|
}
|
|
350
330
|
}
|
|
351
|
-
|
|
352
|
-
return this.#zone ? this.#zone.runOutsideAngular(callback) : callback();
|
|
353
|
-
}
|
|
354
|
-
/**********************
|
|
355
|
-
*
|
|
356
|
-
* LEGACY STUFF TO HANDLE EXISTING POSITIONS
|
|
357
|
-
*
|
|
358
|
-
***********************/
|
|
331
|
+
// Legacy position builder to handle existing position API
|
|
359
332
|
legacyPositionBuilder() {
|
|
360
333
|
const connectionPosition = {
|
|
361
334
|
originX: 'start',
|
|
@@ -442,12 +415,6 @@ class LuTooltipTriggerDirective {
|
|
|
442
415
|
}
|
|
443
416
|
return x;
|
|
444
417
|
}
|
|
445
|
-
requestClose() {
|
|
446
|
-
this.#action.set('close');
|
|
447
|
-
}
|
|
448
|
-
requestOpen() {
|
|
449
|
-
this.#action.set('open');
|
|
450
|
-
}
|
|
451
418
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: LuTooltipTriggerDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
452
419
|
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.0.8", type: LuTooltipTriggerDirective, isStandalone: true, selector: "[luTooltip]", inputs: { luTooltipInput: { classPropertyName: "luTooltipInput", publicName: "luTooltip", isSignal: true, isRequired: false, transformFunction: null }, luTooltipEnterDelay: { classPropertyName: "luTooltipEnterDelay", publicName: "luTooltipEnterDelay", isSignal: true, isRequired: false, transformFunction: null }, luTooltipLeaveDelay: { classPropertyName: "luTooltipLeaveDelay", publicName: "luTooltipLeaveDelay", isSignal: true, isRequired: false, transformFunction: null }, luTooltipDisabled: { classPropertyName: "luTooltipDisabled", publicName: "luTooltipDisabled", isSignal: true, isRequired: false, transformFunction: null }, luTooltipOnlyForDisplay: { classPropertyName: "luTooltipOnlyForDisplay", publicName: "luTooltipOnlyForDisplay", isSignal: true, isRequired: false, transformFunction: null }, luTooltipPosition: { classPropertyName: "luTooltipPosition", publicName: "luTooltipPosition", isSignal: true, isRequired: false, transformFunction: null }, luTooltipWhenEllipsisInput: { classPropertyName: "luTooltipWhenEllipsisInput", publicName: "luTooltipWhenEllipsis", isSignal: true, isRequired: false, transformFunction: null }, luTooltipAnchor: { classPropertyName: "luTooltipAnchor", publicName: "luTooltipAnchor", isSignal: true, isRequired: false, transformFunction: null }, id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()", "focus": "onFocus()", "blur": "onBlur()" }, properties: { "attr.aria-describedby": "ariaDescribedBy()", "attr.id": "id()" } }, exportAs: ["luTooltip"], ngImport: i0 }); }
|
|
453
420
|
}
|