@dile/ui 3.0.4 → 3.0.6

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.
@@ -53,12 +53,18 @@ export class DileChipTooltip extends LitElement {
53
53
  label: { type: String },
54
54
  message: { type: String },
55
55
  position: { type: String },
56
+ icon: { type: Object },
57
+ arrow: { type: Boolean },
58
+ fadeIn: { type: Boolean },
56
59
  };
57
60
  }
58
61
 
59
62
  constructor() {
60
63
  super();
61
64
  this.position = "bottom";
65
+ this.icon = infoIcon;
66
+ this.arrow = false;
67
+ this.fadeIn = true;
62
68
  }
63
69
 
64
70
  render() {
@@ -67,15 +73,15 @@ export class DileChipTooltip extends LitElement {
67
73
  <dile-tooltip
68
74
  tooltip="${this.message}"
69
75
  position="${this.position}"
70
- fadeIn
71
-
76
+ ?arrow=${this.arrow}
77
+ ?fadeIn=${this.fadeIn}
72
78
  >
73
- <span class="chip">
79
+ <span class="chip" role="button">
74
80
  ${this.label
75
81
  ? html`<span class="label">${this.label}</span>`
76
82
  : ''
77
83
  }
78
- <dile-icon .icon=${infoIcon} class="info"></dile-icon>
84
+ <dile-icon .icon=${this.icon} class="info"></dile-icon>
79
85
  </span>
80
86
  </dile-tooltip>
81
87
  </div>
@@ -15,21 +15,23 @@ export class DileTooltip extends LitElement {
15
15
 
16
16
  .tooltiptext {
17
17
  visibility: hidden;
18
- width: var(--dile-tooltip-width, 120px);
19
- background-color: var(--dile-tooltip-background-color, #e74c3c);
20
- color: var(--dile-tooltip-color, #fff);
18
+ position: fixed;
19
+ max-width: var(--dile-tooltip-width, 120px);
20
+ width: auto;
21
+ background-color: var(--dile-tooltip-background-color, var(--dile-primary-color, #e74c3c));
22
+ color: var(--dile-tooltip-color, var(--dile-on-primary-color, #fff));
21
23
  font-size: var(--dile-tooltip-font-size, 16px);
22
24
  text-align: var(--dile-tooltip-text-align, center);
23
25
  border-radius: var(--dile-tooltip-border-radius, 6px);;
24
26
  padding: var(--dile-tooltip-padding, 5px);
27
+ z-index: 10000;
25
28
  }
26
29
 
27
- .tooltip-top {
28
- position: absolute;
29
- z-index: 1;
30
- bottom: var(--dile-tooltip-top--bottom, 150%);
31
- left: 50%;
32
- margin-left: -60px;
30
+ .tooltip-top,
31
+ .tooltip-bottom,
32
+ .tooltip-left,
33
+ .tooltip-right {
34
+ /* Posicionamiento manejado por JavaScript */
33
35
  }
34
36
 
35
37
  .arrow-top::after {
@@ -37,46 +39,21 @@ export class DileTooltip extends LitElement {
37
39
  position: absolute;
38
40
  top: 100%;
39
41
  left: 50%;
40
- margin-left: -5px;
42
+ transform: translateX(-50%);
41
43
  border-width: 5px;
42
44
  border-style: solid;
43
- border-color: var(--dile-tooltip-background-color, #e74c3c) transparent transparent transparent;
44
- }
45
-
46
- .tooltip-left {
47
- position: absolute;
48
- z-index: 1;
49
- top: -5px;
50
- right: 105%;
45
+ border-color: var(--dile-tooltip-background-color, var(--dile-primary-color, #e74c3c)) transparent transparent transparent;
51
46
  }
52
47
 
53
48
  .arrow-left::after {
54
49
  content: " ";
55
50
  position: absolute;
56
51
  top: 50%;
57
- left: 100%; /* To the right of the tooltip */
58
- margin-top: -5px;
52
+ left: 100%;
53
+ transform: translateY(-50%);
59
54
  border-width: 5px;
60
55
  border-style: solid;
61
- border-color: transparent transparent transparent var(--dile-tooltip-background-color, #e74c3c);
62
- }
63
-
64
- .tooltip-right {
65
- position: absolute;
66
- z-index: 1;
67
- top: -5px;
68
- left: 105%;
69
- }
70
-
71
- .arrow-right::after {
72
- content: " ";
73
- position: absolute;
74
- top: 50%;
75
- right: 100%; /* To the left of the tooltip */
76
- margin-top: -5px;
77
- border-width: 5px;
78
- border-style: solid;
79
- border-color: transparent var(--dile-tooltip-background-color, #e74c3c) transparent transparent;
56
+ border-color: transparent transparent transparent var(--dile-tooltip-background-color, var(--dile-primary-color, #e74c3c));
80
57
  }
81
58
 
82
59
  .arrow-right::after {
@@ -84,18 +61,10 @@ export class DileTooltip extends LitElement {
84
61
  position: absolute;
85
62
  top: 50%;
86
63
  right: 100%;
87
- margin-top: -5px;
64
+ transform: translateY(-50%);
88
65
  border-width: 5px;
89
66
  border-style: solid;
90
- border-color: transparent var(--dile-tooltip-background-color, #e74c3c) transparent transparent;
91
- }
92
-
93
- .tooltip-bottom {
94
- position: absolute;
95
- z-index: 1;
96
- top: 150%;
97
- left: 50%;
98
- margin-left: -60px;
67
+ border-color: transparent var(--dile-tooltip-background-color, var(--dile-primary-color, #e74c3c)) transparent transparent;
99
68
  }
100
69
 
101
70
  .arrow-bottom::after {
@@ -103,7 +72,7 @@ export class DileTooltip extends LitElement {
103
72
  position: absolute;
104
73
  bottom: 100%;
105
74
  left: 50%;
106
- margin-left: -5px;
75
+ transform: translateX(-50%);
107
76
  border-width: 5px;
108
77
  border-style: solid;
109
78
  border-color: transparent transparent var(--dile-tooltip-background-color, #e74c3c) transparent;
@@ -119,6 +88,16 @@ export class DileTooltip extends LitElement {
119
88
  opacity: 1;
120
89
  }
121
90
 
91
+ .tooltiptext:focus-visible {
92
+ outline: var(--dile-tooltip-focus-outline-width, 2px) solid var(--dile-tooltip-focus-outline-color, #12c9e9);
93
+ outline-offset: var(--dile-tooltip-focus-outline-offset, 2px);
94
+ }
95
+
96
+ @media (prefers-reduced-motion: reduce) {
97
+ .animation {
98
+ transition: none;
99
+ }
100
+ }
122
101
  `;
123
102
  }
124
103
 
@@ -137,7 +116,10 @@ export class DileTooltip extends LitElement {
137
116
  fadeIn: { type: Boolean },
138
117
 
139
118
  /** Private property to control mouseovers and mouseouts */
140
- _isMouseover: { type: Boolean }
119
+ _isMouseover: { type: Boolean },
120
+
121
+ /** Private property to track keyboard focus */
122
+ _isFocused: { type: Boolean }
141
123
  };
142
124
  }
143
125
 
@@ -148,6 +130,24 @@ export class DileTooltip extends LitElement {
148
130
  this.arrow = false;
149
131
  this.fadeIn = false;
150
132
  this._isMouseover = false;
133
+ this._isFocused = false;
134
+ this._tooltipId = `dile-tooltip-${Math.random().toString(36).substr(2, 9)}`;
135
+ this._rafId = null;
136
+ // El evento scroll puede dispararse muchas veces por frame (y con
137
+ // capture:true, por cualquier contenedor con scroll interno), así que
138
+ // agrupamos los recálculos con rAF para hacer como mucho uno por frame.
139
+ this._boundUpdateTooltipPosition = () => {
140
+ if (this._rafId) return;
141
+ this._rafId = requestAnimationFrame(() => {
142
+ this._rafId = null;
143
+ this.updateTooltipPosition();
144
+ });
145
+ };
146
+ }
147
+
148
+ disconnectedCallback() {
149
+ super.disconnectedCallback();
150
+ this._removeReflowListeners();
151
151
  }
152
152
 
153
153
  classPosition(position) {
@@ -166,20 +166,27 @@ export class DileTooltip extends LitElement {
166
166
  return fadeIn ? 'animation' : '';
167
167
  }
168
168
 
169
- showOrNot(isMouseover) {
170
- return isMouseover ? 'show' : '';
169
+ showOrNot(isMouseover, isFocused) {
170
+ return isMouseover || isFocused ? 'show' : '';
171
171
  }
172
172
 
173
173
  render() {
174
174
  return html`
175
175
  <div
176
176
  class="tooltip"
177
- @mouseover="${this.doMouseover}"
178
- @mouseout="${this.doMouseout}"
177
+ tabindex="0"
178
+ @mouseover=${this.doMouseover}
179
+ @mouseout=${this.doMouseout}
180
+ @focusin=${this.doFocusin}
181
+ @focusout=${this.doFocusout}
182
+ @keydown=${this.doKeydown}
179
183
  >
180
184
  <slot></slot>
181
185
  <span
182
- class="tooltiptext ${this.classPosition(this.position)} ${this.arrowPosition(this.arrow, this.position)} ${this.animation(this.fadeIn)} ${this.showOrNot(this._isMouseover)}"
186
+ id="${this._tooltipId}"
187
+ role="tooltip"
188
+ ?aria-hidden=${!(this._isMouseover || this._isFocused)}
189
+ class="tooltiptext ${this.classPosition(this.position)} ${this.arrowPosition(this.arrow, this.position)} ${this.animation(this.fadeIn)} ${this.showOrNot(this._isMouseover, this._isFocused)}"
183
190
  >${this.tooltip}</span>
184
191
  </div>
185
192
  `;
@@ -192,4 +199,88 @@ export class DileTooltip extends LitElement {
192
199
  doMouseout() {
193
200
  this._isMouseover = false;
194
201
  }
202
+
203
+ doFocusin() {
204
+ this._isFocused = true;
205
+ }
206
+
207
+ doFocusout() {
208
+ this._isFocused = false;
209
+ }
210
+
211
+ doKeydown(event) {
212
+ if (event.key === 'Escape') {
213
+ this._isFocused = false;
214
+ }
215
+ }
216
+
217
+ updated(changedProperties) {
218
+ super.updated(changedProperties);
219
+ if (changedProperties.has('_isMouseover') || changedProperties.has('_isFocused')) {
220
+ if (this._isMouseover || this._isFocused) {
221
+ this.updateTooltipPosition();
222
+ // position:fixed no sigue al trigger si la página hace scroll
223
+ // mientras el tooltip está abierto, así que hay que recalcular a mano.
224
+ this._addReflowListeners();
225
+ } else {
226
+ this._removeReflowListeners();
227
+ }
228
+ }
229
+ }
230
+
231
+ _addReflowListeners() {
232
+ window.addEventListener('scroll', this._boundUpdateTooltipPosition, { capture: true, passive: true });
233
+ window.addEventListener('resize', this._boundUpdateTooltipPosition);
234
+ }
235
+
236
+ _removeReflowListeners() {
237
+ window.removeEventListener('scroll', this._boundUpdateTooltipPosition, { capture: true });
238
+ window.removeEventListener('resize', this._boundUpdateTooltipPosition);
239
+ if (this._rafId) {
240
+ cancelAnimationFrame(this._rafId);
241
+ this._rafId = null;
242
+ }
243
+ }
244
+
245
+ updateTooltipPosition() {
246
+ // Esperar a que el DOM se actualice antes de calcular posiciones
247
+ this.updateComplete.then(() => {
248
+ const tooltip = this.shadowRoot.querySelector('.tooltiptext');
249
+ const trigger = this.shadowRoot.querySelector('.tooltip');
250
+
251
+ if (!tooltip || !trigger) return;
252
+
253
+ const triggerRect = trigger.getBoundingClientRect();
254
+ const gap = 5; // Espacio entre trigger y tooltip
255
+
256
+ let top, left;
257
+
258
+ switch (this.position) {
259
+ case 'top':
260
+ top = triggerRect.top - tooltip.offsetHeight - gap;
261
+ left = triggerRect.left + triggerRect.width / 2 - tooltip.offsetWidth / 2;
262
+ break;
263
+ case 'bottom':
264
+ top = triggerRect.bottom + gap;
265
+ left = triggerRect.left + triggerRect.width / 2 - tooltip.offsetWidth / 2;
266
+ break;
267
+ case 'left':
268
+ top = triggerRect.top + triggerRect.height / 2 - tooltip.offsetHeight / 2;
269
+ left = triggerRect.left - tooltip.offsetWidth - gap;
270
+ break;
271
+ case 'right':
272
+ top = triggerRect.top + triggerRect.height / 2 - tooltip.offsetHeight / 2;
273
+ left = triggerRect.right + gap;
274
+ break;
275
+ default:
276
+ top = triggerRect.top - tooltip.offsetHeight - gap;
277
+ left = triggerRect.left + triggerRect.width / 2 - tooltip.offsetWidth / 2;
278
+ }
279
+
280
+ // Con position:fixed, getBoundingClientRect() ya es relativo al viewport,
281
+ // no hay que sumar el scroll (eso solo aplica a position:absolute).
282
+ tooltip.style.top = top + 'px';
283
+ tooltip.style.left = left + 'px';
284
+ });
285
+ }
195
286
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dile/ui",
3
- "version": "3.0.4",
3
+ "version": "3.0.6",
4
4
  "description": "UI Core components from dile-components.",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -27,5 +27,5 @@
27
27
  "publishConfig": {
28
28
  "access": "public"
29
29
  },
30
- "gitHead": "1d59717e79d41152fc06792784258eab42f0035b"
30
+ "gitHead": "ce6edd61000dafbd2e31064d3031837befc1abb9"
31
31
  }