@marianmeres/stuic 2.25.0 → 2.27.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
  *
@@ -67,6 +93,8 @@ export interface PopoverOptions {
67
93
  debug?: boolean;
68
94
  /** Programmatically control open state (reactive) */
69
95
  open?: boolean;
96
+ /** Unique ID for registry-based programmatic control (use with openPopover/closePopover/togglePopover) */
97
+ id?: string;
70
98
  }
71
99
  /**
72
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;
@@ -201,11 +249,20 @@ export function popover(anchorEl, fn) {
201
249
  if (popoverEl &&
202
250
  !popoverEl.contains(e.target) &&
203
251
  !anchorEl.contains(e.target)) {
252
+ // Skip if an open was just requested via registry (same click event)
253
+ if (openRequestedThisCycle) {
254
+ return;
255
+ }
204
256
  hide();
205
257
  }
206
258
  }
207
259
  function onClickTrigger(e) {
208
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
+ });
209
266
  if (isVisible)
210
267
  hide();
211
268
  else
@@ -409,8 +466,22 @@ export function popover(anchorEl, fn) {
409
466
  onShow: opts.onShow,
410
467
  onHide: opts.onHide,
411
468
  debug: opts.debug,
469
+ id: opts.id,
412
470
  };
413
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
+ }
414
485
  // Update popover if visible
415
486
  if (isVisible && popoverEl) {
416
487
  // Update position (only in anchor positioning mode)
@@ -473,6 +544,10 @@ export function popover(anchorEl, fn) {
473
544
  clearTimers();
474
545
  // Unregister from open popovers
475
546
  openPopovers.delete(hide);
547
+ // Unregister from popover registry
548
+ if (currentOptions.id) {
549
+ popoverRegistry.delete(currentOptions.id);
550
+ }
476
551
  document.removeEventListener("keydown", onEscape);
477
552
  document.removeEventListener("click", onClickOutside);
478
553
  };
@@ -43,8 +43,9 @@
43
43
  border-button-border dark:border-button-border-dark
44
44
  rounded-md
45
45
  inline-flex items-center justify-center gap-x-2
46
- px-3 py-2.5
46
+ px-4 py-3
47
47
  select-none
48
+ min-h-[44px] min-w-[44px]
48
49
 
49
50
  hover:brightness-105
50
51
  active:brightness-95
@@ -59,7 +60,7 @@
59
60
 
60
61
  export const BUTTON_STUIC_PRESET_CLASSES: ButtonPresetClasses = {
61
62
  size: {
62
- sm: `text-sm rounded-sm px-2 py-1`,
63
+ sm: `text-sm rounded-sm px-3 py-2 min-h-none min-w-none`,
63
64
  lg: `text-base rounded-md`,
64
65
  },
65
66
  variant: {
@@ -31,7 +31,7 @@ export interface ButtonPresetClasses {
31
31
  shadow: string;
32
32
  inverse: string;
33
33
  }
34
- export declare const BUTTON_STUIC_BASE_CLASSES = "\n\t\tbg-button-bg text-button-text\n\t\tdark:bg-button-bg-dark dark:text-button-text-dark\n\t\tfont-mono text-sm text-center\n\t\tleading-none\n\t\tborder-1\n\t\tborder-button-border dark:border-button-border-dark\n\t\trounded-md\n\t\tinline-flex items-center justify-center gap-x-2\n\t\tpx-3 py-2.5\n\t\tselect-none\n\n\t\thover:brightness-105\n\t\tactive:brightness-95\n\t\tdisabled:hover:brightness-100 disabled:opacity-50\n\n\t\tfocus:brightness-105\n\t\tfocus:border-button-border-focus focus:dark:border-button-border-focus-dark\n\n\t\t focus:outline-4 focus:outline-black/10 focus:dark:outline-white/20\n\t\tfocus-visible:outline-4 focus-visible:outline-black/10 focus-visible:dark:outline-white/20\n\t";
34
+ export declare const BUTTON_STUIC_BASE_CLASSES = "\n\t\tbg-button-bg text-button-text\n\t\tdark:bg-button-bg-dark dark:text-button-text-dark\n\t\tfont-mono text-sm text-center\n\t\tleading-none\n\t\tborder-1\n\t\tborder-button-border dark:border-button-border-dark\n\t\trounded-md\n\t\tinline-flex items-center justify-center gap-x-2\n\t\tpx-4 py-3\n\t\tselect-none\n\t\tmin-h-[44px] min-w-[44px]\n\n\t\thover:brightness-105\n\t\tactive:brightness-95\n\t\tdisabled:hover:brightness-100 disabled:opacity-50\n\n\t\tfocus:brightness-105\n\t\tfocus:border-button-border-focus focus:dark:border-button-border-focus-dark\n\n\t\t focus:outline-4 focus:outline-black/10 focus:dark:outline-white/20\n\t\tfocus-visible:outline-4 focus-visible:outline-black/10 focus-visible:dark:outline-white/20\n\t";
35
35
  export declare const BUTTON_STUIC_PRESET_CLASSES: ButtonPresetClasses;
36
36
  import "./index.css";
37
37
  import { type TooltipConfig } from "../../actions/index.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "2.25.0",
3
+ "version": "2.27.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",