@marianmeres/stuic 2.58.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.
- package/dist/actions/tooltip/tooltip.svelte.d.ts +20 -0
- package/dist/actions/tooltip/tooltip.svelte.js +41 -1
- package/dist/components/AppShell/AppShell.svelte +2 -2
- package/dist/components/AppShell/AppShell.svelte.d.ts +1 -1
- package/dist/components/AppShell/AppShellSimple.svelte +8 -3
- package/dist/components/AppShell/AppShellSimple.svelte.d.ts +2 -1
- package/dist/components/AppShell/index.d.ts +2 -2
- package/dist/components/AppShell/index.js +2 -2
- package/dist/components/Backdrop/Backdrop.svelte +13 -7
- package/dist/components/Backdrop/Backdrop.svelte.d.ts +1 -0
- package/dist/components/Input/_internal/InputWrap.svelte +1 -0
- package/dist/components/Modal/Modal.svelte +4 -0
- package/dist/components/Modal/Modal.svelte.d.ts +2 -0
- package/dist/index.css +8 -1
- package/package.json +1 -1
|
@@ -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();
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
elFooter?: HTMLElement;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
-
export const
|
|
41
|
+
export const APP_SHELL_MAIN_WIDTH = Symbol("APP_SHELL_MAIN_WIDTH");
|
|
42
42
|
|
|
43
43
|
/**
|
|
44
44
|
* Helper utility function which sets document.body height to 100vh, and overflow: hidden.
|
|
@@ -103,7 +103,7 @@
|
|
|
103
103
|
|
|
104
104
|
// pragmatic use case...
|
|
105
105
|
let mainWidth: number = $state(0);
|
|
106
|
-
setContext(
|
|
106
|
+
setContext(APP_SHELL_MAIN_WIDTH, {
|
|
107
107
|
get current() {
|
|
108
108
|
return mainWidth;
|
|
109
109
|
},
|
|
@@ -33,7 +33,7 @@ export interface Props {
|
|
|
33
33
|
elSidebarRight?: HTMLElement;
|
|
34
34
|
elFooter?: HTMLElement;
|
|
35
35
|
}
|
|
36
|
-
export declare const
|
|
36
|
+
export declare const APP_SHELL_MAIN_WIDTH: unique symbol;
|
|
37
37
|
/**
|
|
38
38
|
* Helper utility function which sets document.body height to 100vh, and overflow: hidden.
|
|
39
39
|
* It also returns a function which unsets the full height. So we can write:
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
railClass?: string;
|
|
10
10
|
asideClass?: string;
|
|
11
11
|
mainClass?: string;
|
|
12
|
+
// header support style as well (for iOS theming, seem to be better supported)
|
|
13
|
+
headerStyle?: string;
|
|
12
14
|
//
|
|
13
15
|
rail?: Snippet;
|
|
14
16
|
header?: Snippet;
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
elMain?: HTMLElement;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
export const
|
|
26
|
+
export const APP_SHELL_SIMPLE_MAIN_WIDTH = Symbol("APP_SHELL_SIMPLE_MAIN_WIDTH");
|
|
25
27
|
</script>
|
|
26
28
|
|
|
27
29
|
<script lang="ts">
|
|
@@ -33,6 +35,8 @@
|
|
|
33
35
|
asideClass,
|
|
34
36
|
mainClass,
|
|
35
37
|
//
|
|
38
|
+
headerStyle = "",
|
|
39
|
+
//
|
|
36
40
|
rail,
|
|
37
41
|
header,
|
|
38
42
|
aside,
|
|
@@ -48,7 +52,7 @@
|
|
|
48
52
|
|
|
49
53
|
// pragmatic use case...
|
|
50
54
|
let mainWidth: number = $state(0);
|
|
51
|
-
setContext(
|
|
55
|
+
setContext(APP_SHELL_SIMPLE_MAIN_WIDTH, {
|
|
52
56
|
get current() {
|
|
53
57
|
return mainWidth;
|
|
54
58
|
},
|
|
@@ -61,6 +65,7 @@
|
|
|
61
65
|
bind:clientHeight={headerHeight}
|
|
62
66
|
data-shell="header"
|
|
63
67
|
class={twMerge("sticky top-0 z-10", headerClass)}
|
|
68
|
+
style={headerStyle}
|
|
64
69
|
>
|
|
65
70
|
{@render header()}
|
|
66
71
|
</header>
|
|
@@ -106,7 +111,7 @@
|
|
|
106
111
|
<main
|
|
107
112
|
bind:this={elMain}
|
|
108
113
|
data-shell="main"
|
|
109
|
-
class={twMerge("flex-1", mainClass)}
|
|
114
|
+
class={twMerge("flex-1 max-w-full", mainClass)}
|
|
110
115
|
bind:offsetWidth={mainWidth}
|
|
111
116
|
>
|
|
112
117
|
{@render children?.()}
|
|
@@ -5,6 +5,7 @@ export interface Props {
|
|
|
5
5
|
railClass?: string;
|
|
6
6
|
asideClass?: string;
|
|
7
7
|
mainClass?: string;
|
|
8
|
+
headerStyle?: string;
|
|
8
9
|
rail?: Snippet;
|
|
9
10
|
header?: Snippet;
|
|
10
11
|
aside?: Snippet;
|
|
@@ -14,7 +15,7 @@ export interface Props {
|
|
|
14
15
|
elAside?: HTMLElement;
|
|
15
16
|
elMain?: HTMLElement;
|
|
16
17
|
}
|
|
17
|
-
export declare const
|
|
18
|
+
export declare const APP_SHELL_SIMPLE_MAIN_WIDTH: unique symbol;
|
|
18
19
|
declare const AppShellSimple: import("svelte").Component<Props, {}, "elRail" | "elHeader" | "elAside" | "elMain">;
|
|
19
20
|
type AppShellSimple = ReturnType<typeof AppShellSimple>;
|
|
20
21
|
export default AppShellSimple;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as AppShell, type Props as AppShellProps, appShellSetHtmlBodyHeight,
|
|
2
|
-
export { default as AppShellSimple, type Props as AppShellSimpleProps,
|
|
1
|
+
export { default as AppShell, type Props as AppShellProps, appShellSetHtmlBodyHeight, APP_SHELL_MAIN_WIDTH, } from "./AppShell.svelte";
|
|
2
|
+
export { default as AppShellSimple, type Props as AppShellSimpleProps, APP_SHELL_SIMPLE_MAIN_WIDTH, } from "./AppShellSimple.svelte";
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { default as AppShell, appShellSetHtmlBodyHeight,
|
|
2
|
-
export { default as AppShellSimple,
|
|
1
|
+
export { default as AppShell, appShellSetHtmlBodyHeight, APP_SHELL_MAIN_WIDTH, } from "./AppShell.svelte";
|
|
2
|
+
export { default as AppShellSimple, APP_SHELL_SIMPLE_MAIN_WIDTH, } from "./AppShellSimple.svelte";
|
|
@@ -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
|
-
|
|
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?.()}
|
|
@@ -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
|
-
|
|
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 *));
|