spoko-design-system 1.35.0 → 1.36.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/CHANGELOG.md +12 -0
- package/package.json +1 -1
- package/src/scripts/tooltips.ts +43 -10
- package/src/styles/sds-tooltip.css +9 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [1.36.0](https://github.com/polo-blue/sds/compare/v1.35.1...v1.36.0) (2026-03-24)
|
|
2
|
+
|
|
3
|
+
### Features
|
|
4
|
+
|
|
5
|
+
* add interactive tooltip mode ([#410](https://github.com/polo-blue/sds/issues/410)) ([473a586](https://github.com/polo-blue/sds/commit/473a5869a765af1b347b2e909f4019bacf3255fd))
|
|
6
|
+
|
|
7
|
+
## [1.35.1](https://github.com/polo-blue/sds/compare/v1.35.0...v1.35.1) (2026-03-24)
|
|
8
|
+
|
|
9
|
+
### Bug Fixes
|
|
10
|
+
|
|
11
|
+
* tooltip listeners lost after Astro View Transitions ([#409](https://github.com/polo-blue/sds/issues/409)) ([4fe9dd4](https://github.com/polo-blue/sds/commit/4fe9dd4d80a15edad47c277c233fb153072a2619))
|
|
12
|
+
|
|
1
13
|
## [1.35.0](https://github.com/polo-blue/sds/compare/v1.34.26...v1.35.0) (2026-03-24)
|
|
2
14
|
|
|
3
15
|
### ⚠ BREAKING CHANGES
|
package/package.json
CHANGED
package/src/scripts/tooltips.ts
CHANGED
|
@@ -2,12 +2,13 @@
|
|
|
2
2
|
* SDS Tooltip Engine
|
|
3
3
|
* Powered by Floating UI — replaces tippy.js
|
|
4
4
|
*
|
|
5
|
-
* Uses event delegation on document
|
|
5
|
+
* Uses event delegation on document (capture phase) for performance.
|
|
6
6
|
* Handles tooltips for any element with [data-sds-tooltip] attribute.
|
|
7
7
|
*
|
|
8
8
|
* Supported attributes:
|
|
9
|
-
* - data-sds-tooltip
|
|
10
|
-
* - data-sds-tooltip-placement
|
|
9
|
+
* - data-sds-tooltip — HTML content to display
|
|
10
|
+
* - data-sds-tooltip-placement — placement override (default: 'top')
|
|
11
|
+
* - data-sds-tooltip-interactive — allow hovering over tooltip (for clickable links)
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
import { computePosition, autoUpdate, offset, flip, shift, arrow, type Placement } from '@floating-ui/dom';
|
|
@@ -19,6 +20,7 @@ const ARROW_SIZE = 8;
|
|
|
19
20
|
const SHIFT_PADDING = 5;
|
|
20
21
|
const SHOW_DELAY = 80;
|
|
21
22
|
const HIDE_DELAY = 60;
|
|
23
|
+
const INTERACTIVE_HIDE_DELAY = 150;
|
|
22
24
|
|
|
23
25
|
let tooltipEl: HTMLElement | null = null;
|
|
24
26
|
let arrowEl: HTMLElement | null = null;
|
|
@@ -28,6 +30,7 @@ let currentTarget: HTMLElement | null = null;
|
|
|
28
30
|
let showTimer: ReturnType<typeof setTimeout> | null = null;
|
|
29
31
|
let hideTimer: ReturnType<typeof setTimeout> | null = null;
|
|
30
32
|
let initialized = false;
|
|
33
|
+
let isInteractive = false;
|
|
31
34
|
|
|
32
35
|
const OPPOSITE_SIDE: Record<string, string> = {
|
|
33
36
|
top: 'bottom',
|
|
@@ -125,6 +128,10 @@ export function showTooltip(target: HTMLElement) {
|
|
|
125
128
|
tooltip.style.display = 'block';
|
|
126
129
|
currentTarget = target;
|
|
127
130
|
|
|
131
|
+
// Interactive mode: allow hovering over tooltip for clickable content
|
|
132
|
+
isInteractive = target.hasAttribute('data-sds-tooltip-interactive');
|
|
133
|
+
tooltip.classList.toggle('sds-tooltip--interactive', isInteractive);
|
|
134
|
+
|
|
128
135
|
// Start auto-updating position
|
|
129
136
|
cleanupAutoUpdate?.();
|
|
130
137
|
cleanupAutoUpdate = autoUpdate(target, tooltip, () => {
|
|
@@ -155,7 +162,18 @@ export function hideTooltip() {
|
|
|
155
162
|
}
|
|
156
163
|
|
|
157
164
|
function handleMouseEnter(e: Event) {
|
|
158
|
-
const
|
|
165
|
+
const el = e.target as HTMLElement;
|
|
166
|
+
|
|
167
|
+
// Hovering over the tooltip itself — cancel pending hide
|
|
168
|
+
if (isInteractive && tooltipEl && (el === tooltipEl || tooltipEl.contains(el))) {
|
|
169
|
+
if (hideTimer) {
|
|
170
|
+
clearTimeout(hideTimer);
|
|
171
|
+
hideTimer = null;
|
|
172
|
+
}
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const target = el.closest?.(SELECTOR);
|
|
159
177
|
if (!(target instanceof HTMLElement)) return;
|
|
160
178
|
|
|
161
179
|
if (hideTimer) {
|
|
@@ -171,7 +189,18 @@ function handleMouseEnter(e: Event) {
|
|
|
171
189
|
}
|
|
172
190
|
|
|
173
191
|
function handleMouseLeave(e: Event) {
|
|
174
|
-
const
|
|
192
|
+
const el = e.target as HTMLElement;
|
|
193
|
+
|
|
194
|
+
// Leaving the tooltip itself — schedule hide
|
|
195
|
+
if (isInteractive && tooltipEl && (el === tooltipEl || tooltipEl.contains(el))) {
|
|
196
|
+
hideTimer = setTimeout(() => {
|
|
197
|
+
hideTooltip();
|
|
198
|
+
hideTimer = null;
|
|
199
|
+
}, INTERACTIVE_HIDE_DELAY);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const target = el.closest?.(SELECTOR);
|
|
175
204
|
if (!(target instanceof HTMLElement)) return;
|
|
176
205
|
|
|
177
206
|
if (showTimer) {
|
|
@@ -179,10 +208,11 @@ function handleMouseLeave(e: Event) {
|
|
|
179
208
|
showTimer = null;
|
|
180
209
|
}
|
|
181
210
|
|
|
211
|
+
const delay = isInteractive ? INTERACTIVE_HIDE_DELAY : HIDE_DELAY;
|
|
182
212
|
hideTimer = setTimeout(() => {
|
|
183
213
|
hideTooltip();
|
|
184
214
|
hideTimer = null;
|
|
185
|
-
},
|
|
215
|
+
}, delay);
|
|
186
216
|
}
|
|
187
217
|
|
|
188
218
|
function handleFocusIn(e: Event) {
|
|
@@ -203,10 +233,13 @@ export function initTooltips() {
|
|
|
203
233
|
if (initialized) return;
|
|
204
234
|
initialized = true;
|
|
205
235
|
|
|
206
|
-
document.body
|
|
207
|
-
|
|
208
|
-
document
|
|
209
|
-
document.
|
|
236
|
+
// Use `document` instead of `document.body` — Astro View Transitions
|
|
237
|
+
// replace the <body> element during swap, which would lose listeners.
|
|
238
|
+
// `document` persists across navigations.
|
|
239
|
+
document.addEventListener('mouseenter', handleMouseEnter, true);
|
|
240
|
+
document.addEventListener('mouseleave', handleMouseLeave, true);
|
|
241
|
+
document.addEventListener('focusin', handleFocusIn, true);
|
|
242
|
+
document.addEventListener('focusout', handleFocusOut, true);
|
|
210
243
|
}
|
|
211
244
|
|
|
212
245
|
function cleanup() {
|
|
@@ -30,6 +30,15 @@
|
|
|
30
30
|
opacity: 1;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
/* Interactive mode — allow hovering over tooltip for clickable content */
|
|
34
|
+
.sds-tooltip--interactive {
|
|
35
|
+
pointer-events: auto;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.sds-tooltip--interactive a {
|
|
39
|
+
pointer-events: auto;
|
|
40
|
+
}
|
|
41
|
+
|
|
33
42
|
/* Arrow */
|
|
34
43
|
.sds-tooltip-arrow {
|
|
35
44
|
position: absolute;
|