@marianmeres/stuic 2.59.0 → 2.60.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.
@@ -45,6 +45,26 @@ export type TooltipConfig = () => {
45
45
  onShow?: CallableFunction;
46
46
  onHide?: CallableFunction;
47
47
  };
48
+ /**
49
+ * Globally enable or disable all tooltips.
50
+ * Useful for disabling tooltips on touch devices where they interfere with interactions.
51
+ *
52
+ * @param value - `true` to enable tooltips, `false` to disable
53
+ *
54
+ * @example
55
+ * ```ts
56
+ * // Disable tooltips on touch devices
57
+ * if ('ontouchstart' in window) {
58
+ * setTooltipsEnabled(false);
59
+ * }
60
+ * ```
61
+ */
62
+ export declare function setTooltipsEnabled(value: boolean): void;
63
+ /**
64
+ * Get the current global tooltip enabled state.
65
+ * @returns `true` if tooltips are globally enabled, `false` otherwise
66
+ */
67
+ export declare function getTooltipsEnabled(): boolean;
48
68
  /**
49
69
  * A Svelte action that displays a tooltip anchored to an element using CSS Anchor Positioning.
50
70
  *
@@ -48,6 +48,44 @@ const POSITION_MAP = {
48
48
  left: "left",
49
49
  right: "right",
50
50
  };
51
+ // Global tooltip configuration - allows disabling all tooltips at runtime
52
+ const globalTooltipConfig = $state({ enabled: true });
53
+ // Touch device auto-detection (runs once on first tooltip init)
54
+ let touchDetectionDone = false;
55
+ function detectTouchDevice() {
56
+ if (touchDetectionDone)
57
+ return;
58
+ touchDetectionDone = true;
59
+ // Detect touch device and disable tooltips by default
60
+ const isTouchDevice = "ontouchstart" in window || navigator.maxTouchPoints > 0;
61
+ if (isTouchDevice) {
62
+ globalTooltipConfig.enabled = false;
63
+ }
64
+ }
65
+ /**
66
+ * Globally enable or disable all tooltips.
67
+ * Useful for disabling tooltips on touch devices where they interfere with interactions.
68
+ *
69
+ * @param value - `true` to enable tooltips, `false` to disable
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * // Disable tooltips on touch devices
74
+ * if ('ontouchstart' in window) {
75
+ * setTooltipsEnabled(false);
76
+ * }
77
+ * ```
78
+ */
79
+ export function setTooltipsEnabled(value) {
80
+ globalTooltipConfig.enabled = value;
81
+ }
82
+ /**
83
+ * Get the current global tooltip enabled state.
84
+ * @returns `true` if tooltips are globally enabled, `false` otherwise
85
+ */
86
+ export function getTooltipsEnabled() {
87
+ return globalTooltipConfig.enabled;
88
+ }
51
89
  /**
52
90
  * A Svelte action that displays a tooltip anchored to an element using CSS Anchor Positioning.
53
91
  *
@@ -88,6 +126,8 @@ export function tooltip(anchorEl, fn) {
88
126
  // the node has been mounted in the DOM
89
127
  if (!isTooltipSupported())
90
128
  return;
129
+ // Auto-detect touch device on first tooltip init
130
+ detectTouchDevice();
91
131
  //
92
132
  let tooltipEl;
93
133
  let hide_timer = null;
@@ -215,7 +255,7 @@ export function tooltip(anchorEl, fn) {
215
255
  on_hide = onHide;
216
256
  content = _content || anchorEl.getAttribute("aria-label");
217
257
  classTooltip = _classTooltip;
218
- enabled = _enabled ?? true;
258
+ enabled = globalTooltipConfig.enabled && (_enabled ?? true);
219
259
  position = _position || "top";
220
260
  // this will be effective here only if currently in open state, otherwise noop
221
261
  set_content();
@@ -1,6 +1,11 @@
1
1
  <script lang="ts" module>
2
2
  import type { Snippet } from "svelte";
3
3
  import type { FocusTrapOptions } from "../../actions/focus-trap.js";
4
+ import { BodyScroll, focusTrap as focusTrapAction, twMerge } from "../../index.js";
5
+ import { createClog } from "@marianmeres/clog";
6
+ import { watch } from "runed";
7
+ import { onDestroy } from "svelte";
8
+ import { fade } from "svelte/transition";
4
9
 
5
10
  export interface Props extends Record<string, any> {
6
11
  class?: string;
@@ -11,6 +16,7 @@
11
16
  el?: HTMLDivElement;
12
17
  children?: Snippet;
13
18
  onEscape?: () => void;
19
+ onBackdropClick?: () => void;
14
20
  visible?: boolean;
15
21
  noScrollLock?: boolean;
16
22
  }
@@ -20,13 +26,7 @@
20
26
  </script>
21
27
 
22
28
  <script lang="ts">
23
- import { BodyScroll, focusTrap as focusTrapAction, twMerge } from "../../index.js";
24
- import { createClog } from "@marianmeres/clog";
25
- import { watch } from "runed";
26
- import { onDestroy } from "svelte";
27
- import { fade } from "svelte/transition";
28
-
29
- const clog = createClog("Backdrop").debug;
29
+ const clog = createClog("Backdrop", { color: "auto" });
30
30
 
31
31
  let {
32
32
  class: classProp,
@@ -37,6 +37,7 @@
37
37
  el = $bindable(),
38
38
  children,
39
39
  onEscape,
40
+ onBackdropClick,
40
41
  visible = $bindable(false),
41
42
  noScrollLock,
42
43
  ...rest
@@ -152,6 +153,11 @@
152
153
  in:fade={{ duration: fadeInDuration }}
153
154
  out:fade={{ duration: fadeOutDuration }}
154
155
  use:focusTrapAction={focusTrapOptions}
156
+ onmousedown={(e) => {
157
+ if (e.target === el && onBackdropClick) {
158
+ onBackdropClick();
159
+ }
160
+ }}
155
161
  {...rest}
156
162
  >
157
163
  {@render children?.()}
@@ -9,6 +9,7 @@ export interface Props extends Record<string, any> {
9
9
  el?: HTMLDivElement;
10
10
  children?: Snippet;
11
11
  onEscape?: () => void;
12
+ onBackdropClick?: () => void;
12
13
  visible?: boolean;
13
14
  noScrollLock?: boolean;
14
15
  }
@@ -105,6 +105,7 @@
105
105
  inputBox: {
106
106
  size: {
107
107
  sm: "text-sm",
108
+ lg: "p-1",
108
109
  } as any,
109
110
  },
110
111
  };
@@ -29,6 +29,8 @@
29
29
  onEscape?: undefined | (() => void);
30
30
  /** Disable body scroll lock when modal is open */
31
31
  noScrollLock?: boolean;
32
+ /** Fires when the backdrop is clicked "directly" */
33
+ onBackdropClick?: undefined | (() => void);
32
34
  }
33
35
  </script>
34
36
 
@@ -59,6 +61,7 @@
59
61
  focusTrap = true,
60
62
  onEscape,
61
63
  noScrollLock = false,
64
+ onBackdropClick,
62
65
  }: Props = $props();
63
66
 
64
67
  let backdrop: Backdrop = $state()!;
@@ -94,6 +97,7 @@
94
97
  fadeOutDuration={transitionDuration}
95
98
  {onEscape}
96
99
  {noScrollLock}
100
+ {onBackdropClick}
97
101
  >
98
102
  <div
99
103
  bind:this={el}
@@ -27,6 +27,8 @@ export interface Props {
27
27
  onEscape?: undefined | (() => void);
28
28
  /** Disable body scroll lock when modal is open */
29
29
  noScrollLock?: boolean;
30
+ /** Fires when the backdrop is clicked "directly" */
31
+ onBackdropClick?: undefined | (() => void);
30
32
  }
31
33
  declare const Modal: import("svelte").Component<Props, {
32
34
  close: () => void;
package/dist/index.css CHANGED
@@ -1,4 +1,11 @@
1
- @import "tailwindcss";
1
+ /*
2
+ Tailwind import removed here because it causes CSS cascade/layer issues in WebKit browsers
3
+ (Safari, iOS Chrome) when consumers also import Tailwind. The double import can result in
4
+ Tailwind's preflight styles (like border-style: solid) not being applied correctly.
5
+ Consumers of STUIC should import Tailwind at their own app level.
6
+ */
7
+ /* @import "tailwindcss"; */
8
+
2
9
  @plugin '@tailwindcss/forms';
3
10
 
4
11
  @custom-variant dark (&:where(.dark, .dark *));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@marianmeres/stuic",
3
- "version": "2.59.0",
3
+ "version": "2.60.0",
4
4
  "files": [
5
5
  "dist",
6
6
  "!dist/**/*.test.*",