@marianmeres/stuic 2.23.0 → 2.26.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.
|
@@ -1,5 +1,31 @@
|
|
|
1
1
|
import type { THC } from "../../components/Thc/Thc.svelte";
|
|
2
2
|
import "./index.css";
|
|
3
|
+
/**
|
|
4
|
+
* Open a popover by its registered ID.
|
|
5
|
+
*
|
|
6
|
+
* @param id - The popover ID to open
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```svelte
|
|
10
|
+
* <script>
|
|
11
|
+
* import { openPopover } from './';
|
|
12
|
+
* </script>
|
|
13
|
+
* <button onclick={() => openPopover('my-popover')}>Open</button>
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function openPopover(id: string): void;
|
|
17
|
+
/**
|
|
18
|
+
* Close a popover by its registered ID.
|
|
19
|
+
*
|
|
20
|
+
* @param id - The popover ID to close
|
|
21
|
+
*/
|
|
22
|
+
export declare function closePopover(id: string): void;
|
|
23
|
+
/**
|
|
24
|
+
* Toggle a popover by its registered ID.
|
|
25
|
+
*
|
|
26
|
+
* @param id - The popover ID to toggle
|
|
27
|
+
*/
|
|
28
|
+
export declare function togglePopover(id: string): void;
|
|
3
29
|
/**
|
|
4
30
|
* Checks if the browser supports CSS Anchor Positioning for popovers.
|
|
5
31
|
*
|
|
@@ -65,6 +91,10 @@ export interface PopoverOptions {
|
|
|
65
91
|
onHide?: () => void;
|
|
66
92
|
/** Debug mode */
|
|
67
93
|
debug?: boolean;
|
|
94
|
+
/** Programmatically control open state (reactive) */
|
|
95
|
+
open?: boolean;
|
|
96
|
+
/** Unique ID for registry-based programmatic control (use with openPopover/closePopover/togglePopover) */
|
|
97
|
+
id?: string;
|
|
68
98
|
}
|
|
69
99
|
/**
|
|
70
100
|
* A Svelte action that displays a popover anchored to an element using CSS Anchor Positioning.
|
|
@@ -6,6 +6,54 @@ import PopoverContent from "./PopoverContent.svelte";
|
|
|
6
6
|
import "./index.css";
|
|
7
7
|
// Registry of open popover hide functions for closeOthers feature
|
|
8
8
|
const openPopovers = new Set();
|
|
9
|
+
// Registry of popovers by ID for programmatic control
|
|
10
|
+
const popoverRegistry = new Map();
|
|
11
|
+
// Track if an open was just requested (to prevent same-click outside close)
|
|
12
|
+
let openRequestedThisCycle = false;
|
|
13
|
+
/**
|
|
14
|
+
* Open a popover by its registered ID.
|
|
15
|
+
*
|
|
16
|
+
* @param id - The popover ID to open
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```svelte
|
|
20
|
+
* <script>
|
|
21
|
+
* import { openPopover } from './';
|
|
22
|
+
* </script>
|
|
23
|
+
* <button onclick={() => openPopover('my-popover')}>Open</button>
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export function openPopover(id) {
|
|
27
|
+
const entry = popoverRegistry.get(id);
|
|
28
|
+
if (entry) {
|
|
29
|
+
openRequestedThisCycle = true;
|
|
30
|
+
setTimeout(() => {
|
|
31
|
+
openRequestedThisCycle = false;
|
|
32
|
+
}, 0);
|
|
33
|
+
// Close all other open popovers first
|
|
34
|
+
openPopovers.forEach((hideFn) => {
|
|
35
|
+
if (hideFn !== entry.hide)
|
|
36
|
+
hideFn();
|
|
37
|
+
});
|
|
38
|
+
entry.show();
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Close a popover by its registered ID.
|
|
43
|
+
*
|
|
44
|
+
* @param id - The popover ID to close
|
|
45
|
+
*/
|
|
46
|
+
export function closePopover(id) {
|
|
47
|
+
popoverRegistry.get(id)?.hide();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Toggle a popover by its registered ID.
|
|
51
|
+
*
|
|
52
|
+
* @param id - The popover ID to toggle
|
|
53
|
+
*/
|
|
54
|
+
export function togglePopover(id) {
|
|
55
|
+
popoverRegistry.get(id)?.toggle();
|
|
56
|
+
}
|
|
9
57
|
const SHOW_DELAY = 100;
|
|
10
58
|
const HIDE_DELAY = 200;
|
|
11
59
|
const TRANSITION = 200;
|
|
@@ -155,6 +203,7 @@ export function popover(anchorEl, fn) {
|
|
|
155
203
|
let hideTimer = null;
|
|
156
204
|
let isVisible = false;
|
|
157
205
|
let do_debug = false;
|
|
206
|
+
let prevOpen = undefined;
|
|
158
207
|
// Unique identifiers
|
|
159
208
|
const rnd = Math.random().toString(36).slice(2);
|
|
160
209
|
const id = `popover-${rnd}`;
|
|
@@ -200,11 +249,20 @@ export function popover(anchorEl, fn) {
|
|
|
200
249
|
if (popoverEl &&
|
|
201
250
|
!popoverEl.contains(e.target) &&
|
|
202
251
|
!anchorEl.contains(e.target)) {
|
|
252
|
+
// Skip if an open was just requested via registry (same click event)
|
|
253
|
+
if (openRequestedThisCycle) {
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
203
256
|
hide();
|
|
204
257
|
}
|
|
205
258
|
}
|
|
206
259
|
function onClickTrigger(e) {
|
|
207
260
|
e.stopPropagation();
|
|
261
|
+
// Close all other open popovers (since stopPropagation prevents onClickOutside from firing)
|
|
262
|
+
openPopovers.forEach((hideFn) => {
|
|
263
|
+
if (hideFn !== hide)
|
|
264
|
+
hideFn();
|
|
265
|
+
});
|
|
208
266
|
if (isVisible)
|
|
209
267
|
hide();
|
|
210
268
|
else
|
|
@@ -408,8 +466,22 @@ export function popover(anchorEl, fn) {
|
|
|
408
466
|
onShow: opts.onShow,
|
|
409
467
|
onHide: opts.onHide,
|
|
410
468
|
debug: opts.debug,
|
|
469
|
+
id: opts.id,
|
|
411
470
|
};
|
|
412
471
|
do_debug = !!opts.debug;
|
|
472
|
+
// Register in global registry if id provided
|
|
473
|
+
if (opts.id) {
|
|
474
|
+
popoverRegistry.set(opts.id, {
|
|
475
|
+
show,
|
|
476
|
+
hide,
|
|
477
|
+
toggle: () => {
|
|
478
|
+
if (isVisible)
|
|
479
|
+
hide();
|
|
480
|
+
else
|
|
481
|
+
show();
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
}
|
|
413
485
|
// Update popover if visible
|
|
414
486
|
if (isVisible && popoverEl) {
|
|
415
487
|
// Update position (only in anchor positioning mode)
|
|
@@ -421,6 +493,17 @@ export function popover(anchorEl, fn) {
|
|
|
421
493
|
}
|
|
422
494
|
// Note: trigger mode change while visible is not fully handled
|
|
423
495
|
// User should close and reopen for trigger mode change to take effect
|
|
496
|
+
// Handle programmatic open/close
|
|
497
|
+
const openValue = opts.open;
|
|
498
|
+
if (openValue !== undefined && openValue !== prevOpen) {
|
|
499
|
+
if (openValue && !isVisible) {
|
|
500
|
+
show();
|
|
501
|
+
}
|
|
502
|
+
else if (!openValue && isVisible) {
|
|
503
|
+
hide();
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
prevOpen = openValue;
|
|
424
507
|
});
|
|
425
508
|
// Event listeners effect
|
|
426
509
|
$effect(() => {
|
|
@@ -461,6 +544,10 @@ export function popover(anchorEl, fn) {
|
|
|
461
544
|
clearTimers();
|
|
462
545
|
// Unregister from open popovers
|
|
463
546
|
openPopovers.delete(hide);
|
|
547
|
+
// Unregister from popover registry
|
|
548
|
+
if (currentOptions.id) {
|
|
549
|
+
popoverRegistry.delete(currentOptions.id);
|
|
550
|
+
}
|
|
464
551
|
document.removeEventListener("keydown", onEscape);
|
|
465
552
|
document.removeEventListener("click", onClickOutside);
|
|
466
553
|
};
|