@svadmin/ui 0.38.2 → 0.38.5
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/app.css +8 -4
- package/dist/app.theme.css +8 -4
- package/dist/components/AICommandBar.svelte +16 -15
- package/dist/components/AboutSettings.svelte +12 -11
- package/dist/components/AdminApp.svelte +144 -70
- package/dist/components/AdminApp.svelte.d.ts +6 -3
- package/dist/components/ApiSettings.svelte +19 -16
- package/dist/components/AppearanceSettings.svelte +18 -16
- package/dist/components/AuditLogDrawer.svelte +6 -3
- package/dist/components/AuditLogViewer.svelte +18 -15
- package/dist/components/Authenticated.svelte +4 -4
- package/dist/components/AutoForm.svelte +19 -16
- package/dist/components/AutoSaveIndicator.svelte +7 -5
- package/dist/components/AutoTable.svelte +85 -71
- package/dist/components/AutoTable.svelte.d.ts +1 -1
- package/dist/components/Breadcrumbs.svelte +17 -13
- package/dist/components/CancelTaskButton.svelte +5 -2
- package/dist/components/CatchAllNavigate.svelte +3 -3
- package/dist/components/ChatDialog.svelte +22 -19
- package/dist/components/ComboboxField.svelte +6 -4
- package/dist/components/CommandPalette.svelte +20 -20
- package/dist/components/ConfigErrorScreen.svelte +12 -10
- package/dist/components/ConfirmDialog.svelte +6 -4
- package/dist/components/CreatePage.svelte +4 -2
- package/dist/components/DevTools.svelte +11 -9
- package/dist/components/DrawerForm.svelte +5 -2
- package/dist/components/EditPage.svelte +8 -5
- package/dist/components/EmptyState.svelte +5 -3
- package/dist/components/ErrorBoundary.svelte +5 -3
- package/dist/components/ErrorComponent.svelte +6 -4
- package/dist/components/ErrorPage.svelte +12 -10
- package/dist/components/FieldRenderer.svelte +17 -15
- package/dist/components/ForgotPasswordPage.svelte +22 -19
- package/dist/components/Header.svelte +7 -4
- package/dist/components/InfiniteList.svelte +6 -3
- package/dist/components/IntegrationsSettings.svelte +9 -6
- package/dist/components/KeyboardShortcuts.svelte +4 -2
- package/dist/components/Layout.svelte +12 -13
- package/dist/components/LazyPage.svelte +47 -0
- package/dist/components/LazyPage.svelte.d.ts +14 -0
- package/dist/components/ListPage.svelte +8 -5
- package/dist/components/LoginPage.svelte +24 -22
- package/dist/components/MarkdownRenderer.svelte +89 -35
- package/dist/components/ModalForm.svelte +4 -2
- package/dist/components/NavigateToResource.svelte +3 -3
- package/dist/components/NotificationsSettings.svelte +26 -24
- package/dist/components/PasswordInput.svelte +4 -2
- package/dist/components/PermissionMatrix.svelte +15 -12
- package/dist/components/ProfilePage.svelte +23 -21
- package/dist/components/RegisterPage.svelte +21 -19
- package/dist/components/ResourceOperationsPage.svelte +3 -2
- package/dist/components/RetryTaskButton.svelte +5 -2
- package/dist/components/RolesSettings.svelte +10 -8
- package/dist/components/SecuritySettings.svelte +26 -23
- package/dist/components/SettingsPage.svelte +14 -11
- package/dist/components/ShowPage.svelte +9 -7
- package/dist/components/Sidebar.svelte +36 -28
- package/dist/components/SidebarItem.svelte +4 -4
- package/dist/components/SidebarItem.svelte.d.ts +1 -1
- package/dist/components/StepsForm.svelte +11 -8
- package/dist/components/TaskDetails.svelte +14 -11
- package/dist/components/TaskList.svelte +14 -11
- package/dist/components/TaskQueueDrawer.svelte +34 -32
- package/dist/components/TaskStatusBadge.svelte +5 -2
- package/dist/components/Toast.svelte +18 -4
- package/dist/components/TooltipButton.svelte +25 -3
- package/dist/components/TwoFactorAuthPage.svelte +26 -24
- package/dist/components/UndoableNotification.svelte +5 -2
- package/dist/components/UpdatePasswordPage.svelte +18 -15
- package/dist/components/VirtualTable.svelte +0 -4
- package/dist/components/account/CompanyProfilePage.svelte +13 -11
- package/dist/components/account/GetStartedPage.svelte +15 -13
- package/dist/components/account/ImportMembersPage.svelte +14 -12
- package/dist/components/account/MembersStarterPage.svelte +10 -8
- package/dist/components/account/SecurityLogPage.svelte +24 -22
- package/dist/components/account/SettingsEnterprisePage.svelte +6 -4
- package/dist/components/account/SettingsPlainPage.svelte +14 -12
- package/dist/components/account/SettingsSidebarPage.svelte +11 -9
- package/dist/components/account/TeamMembersPage.svelte +10 -8
- package/dist/components/buttons/CloneButton.svelte +4 -2
- package/dist/components/buttons/CreateButton.svelte +4 -2
- package/dist/components/buttons/DeleteButton.svelte +6 -4
- package/dist/components/buttons/EditButton.svelte +4 -2
- package/dist/components/buttons/ExportButton.svelte +4 -2
- package/dist/components/buttons/ImportButton.svelte +4 -2
- package/dist/components/buttons/RefreshButton.svelte +4 -2
- package/dist/components/buttons/SaveButton.svelte +4 -2
- package/dist/components/buttons/ShowButton.svelte +4 -2
- package/dist/components/fieldComponentMap.js +0 -3
- package/dist/components/fields/ArrayField.svelte +6 -4
- package/dist/components/fields/JsonField.svelte +5 -3
- package/dist/components/fields/RelationField.svelte +3 -3
- package/dist/components/fields/RichTextField.svelte +4 -2
- package/dist/components/network/TeamCrewTablePage.svelte +18 -16
- package/dist/components/network/UserCardsNFTPage.svelte +11 -9
- package/dist/components/profile/ActivityTimeline.svelte +10 -8
- package/dist/components/profile/ProfileCard.svelte +13 -11
- package/dist/components/profile/ProjectsGrid.svelte +7 -5
- package/dist/components/profile/PublicProfilePage.svelte +18 -16
- package/dist/components/profile/TeamsShowcase.svelte +7 -5
- package/dist/components/toast-host.svelte.d.ts +5 -0
- package/dist/components/toast-host.svelte.js +21 -0
- package/dist/components/ui/command/command-dialog.svelte +29 -13
- package/dist/components/ui/command/command-dialog.svelte.d.ts +4 -3
- package/dist/components/ui/command/command-empty.svelte +18 -0
- package/dist/components/ui/command/command-empty.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-group.svelte +41 -0
- package/dist/components/ui/command/command-group.svelte.d.ts +8 -0
- package/dist/components/ui/command/command-input.svelte +23 -0
- package/dist/components/ui/command/command-input.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-item.svelte +43 -0
- package/dist/components/ui/command/command-item.svelte.d.ts +11 -0
- package/dist/components/ui/command/command-list.svelte +18 -0
- package/dist/components/ui/command/command-list.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-loading.svelte +12 -0
- package/dist/components/ui/command/command-loading.svelte.d.ts +4 -0
- package/dist/components/ui/command/command-separator.svelte +23 -0
- package/dist/components/ui/command/command-separator.svelte.d.ts +7 -0
- package/dist/components/ui/command/command.svelte +26 -0
- package/dist/components/ui/command/command.svelte.d.ts +4 -0
- package/dist/components/ui/command/index.d.ts +55 -2
- package/dist/components/ui/command/index.js +21 -2
- package/dist/components/ui/sheet/sheet-content.svelte +1 -4
- package/dist/components/ui/sheet/sheet-content.svelte.d.ts +1 -3
- package/dist/components/ui/tabs/tabs-content.svelte +6 -2
- package/dist/components/ui/tabs/tabs-context.svelte.d.ts +5 -0
- package/dist/components/ui/tabs/tabs-context.svelte.js +2 -0
- package/dist/components/ui/tabs/tabs-trigger.svelte +49 -4
- package/dist/components/ui/tabs/tabs.svelte +12 -1
- package/dist/components/ui/tooltip/index.d.ts +4 -1
- package/dist/components/ui/tooltip/index.js +3 -1
- package/dist/components/ui/tooltip/tooltip-content.svelte +308 -35
- package/dist/components/ui/tooltip/tooltip-content.svelte.d.ts +42 -3
- package/dist/components/ui/tooltip/tooltip-context.svelte.d.ts +37 -0
- package/dist/components/ui/tooltip/tooltip-context.svelte.js +220 -0
- package/dist/components/ui/tooltip/tooltip-layer-registry.svelte.d.ts +11 -0
- package/dist/components/ui/tooltip/tooltip-layer-registry.svelte.js +93 -0
- package/dist/components/ui/tooltip/tooltip-trigger.svelte +56 -3
- package/dist/components/ui/tooltip/tooltip-trigger.svelte.d.ts +23 -2
- package/dist/components/ui/tooltip/tooltip.svelte +63 -3
- package/dist/components/ui/tooltip/tooltip.svelte.d.ts +23 -2
- package/dist/router-state.svelte.d.ts +13 -0
- package/dist/router-state.svelte.js +72 -37
- package/package.json +13 -11
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
import { cn, type WithElementRef } from "../../../utils.js";
|
|
3
3
|
import type { HTMLAttributes } from "svelte/elements";
|
|
4
4
|
|
|
5
|
-
type Props = WithElementRef<HTMLAttributes<HTMLDivElement
|
|
6
|
-
side?: "left" | "right";
|
|
7
|
-
};
|
|
5
|
+
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>>;
|
|
8
6
|
|
|
9
7
|
let {
|
|
10
8
|
ref = $bindable(null),
|
|
11
|
-
side = "right",
|
|
12
9
|
class: className,
|
|
13
10
|
children,
|
|
14
11
|
...restProps
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { type WithElementRef } from "../../../utils.js";
|
|
2
2
|
import type { HTMLAttributes } from "svelte/elements";
|
|
3
|
-
type Props = WithElementRef<HTMLAttributes<HTMLDivElement
|
|
4
|
-
side?: "left" | "right";
|
|
5
|
-
};
|
|
3
|
+
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>>;
|
|
6
4
|
declare const SheetContent: import("svelte").Component<Props, {}, "ref">;
|
|
7
5
|
type SheetContent = ReturnType<typeof SheetContent>;
|
|
8
6
|
export default SheetContent;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn, type WithElementRef } from "../../../utils.js";
|
|
3
3
|
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import { getTabsContext } from "./tabs-context.svelte.js";
|
|
4
5
|
|
|
5
6
|
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
|
6
7
|
value: string;
|
|
@@ -10,14 +11,17 @@
|
|
|
10
11
|
let {
|
|
11
12
|
ref = $bindable(null),
|
|
12
13
|
value,
|
|
13
|
-
active
|
|
14
|
+
active,
|
|
14
15
|
class: className,
|
|
15
16
|
children,
|
|
16
17
|
...restProps
|
|
17
18
|
}: Props = $props();
|
|
19
|
+
|
|
20
|
+
const tabs = getTabsContext();
|
|
21
|
+
const isActive = $derived(active ?? tabs.value === value);
|
|
18
22
|
</script>
|
|
19
23
|
|
|
20
|
-
{#if
|
|
24
|
+
{#if isActive}
|
|
21
25
|
<div
|
|
22
26
|
bind:this={ref}
|
|
23
27
|
data-slot="tabs-content"
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { cn, type WithElementRef } from "../../../utils.js";
|
|
3
3
|
import type { HTMLButtonAttributes } from "svelte/elements";
|
|
4
|
+
import { getTabsContext } from "./tabs-context.svelte.js";
|
|
4
5
|
|
|
5
6
|
type Props = WithElementRef<HTMLButtonAttributes, HTMLButtonElement> & {
|
|
6
7
|
value: string;
|
|
@@ -10,11 +11,52 @@
|
|
|
10
11
|
let {
|
|
11
12
|
ref = $bindable(null),
|
|
12
13
|
value,
|
|
13
|
-
active
|
|
14
|
+
active,
|
|
15
|
+
onclick,
|
|
16
|
+
onkeydown,
|
|
17
|
+
tabindex,
|
|
14
18
|
class: className,
|
|
15
19
|
children,
|
|
16
20
|
...restProps
|
|
17
21
|
}: Props = $props();
|
|
22
|
+
|
|
23
|
+
const tabs = getTabsContext();
|
|
24
|
+
const isActive = $derived(active ?? tabs.value === value);
|
|
25
|
+
type ButtonMouseEvent = MouseEvent & { currentTarget: EventTarget & HTMLButtonElement };
|
|
26
|
+
type ButtonKeyboardEvent = KeyboardEvent & { currentTarget: EventTarget & HTMLButtonElement };
|
|
27
|
+
|
|
28
|
+
function handleClick(event: ButtonMouseEvent) {
|
|
29
|
+
onclick?.(event);
|
|
30
|
+
if (!event.defaultPrevented) tabs.select(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function handleKeydown(event: ButtonKeyboardEvent) {
|
|
34
|
+
onkeydown?.(event);
|
|
35
|
+
if (event.defaultPrevented) return;
|
|
36
|
+
|
|
37
|
+
const keys = ["ArrowLeft", "ArrowRight", "ArrowUp", "ArrowDown", "Home", "End"];
|
|
38
|
+
if (!keys.includes(event.key)) return;
|
|
39
|
+
|
|
40
|
+
const tabList = event.currentTarget.closest('[role="tablist"]');
|
|
41
|
+
if (!tabList) return;
|
|
42
|
+
const triggers: HTMLButtonElement[] = Array.from(
|
|
43
|
+
tabList.querySelectorAll<HTMLButtonElement>('[role="tab"]:not(:disabled)')
|
|
44
|
+
);
|
|
45
|
+
const currentIndex = triggers.indexOf(event.currentTarget);
|
|
46
|
+
if (currentIndex === -1 || triggers.length === 0) return;
|
|
47
|
+
|
|
48
|
+
const nextIndex = event.key === "Home"
|
|
49
|
+
? 0
|
|
50
|
+
: event.key === "End"
|
|
51
|
+
? triggers.length - 1
|
|
52
|
+
: event.key === "ArrowRight" || event.key === "ArrowDown"
|
|
53
|
+
? (currentIndex + 1) % triggers.length
|
|
54
|
+
: (currentIndex - 1 + triggers.length) % triggers.length;
|
|
55
|
+
|
|
56
|
+
event.preventDefault();
|
|
57
|
+
triggers[nextIndex]?.focus();
|
|
58
|
+
triggers[nextIndex]?.click();
|
|
59
|
+
}
|
|
18
60
|
</script>
|
|
19
61
|
|
|
20
62
|
<button
|
|
@@ -22,16 +64,19 @@
|
|
|
22
64
|
type="button"
|
|
23
65
|
role="tab"
|
|
24
66
|
data-slot="tabs-trigger"
|
|
25
|
-
data-state={
|
|
26
|
-
aria-selected={
|
|
67
|
+
data-state={isActive ? "active" : "inactive"}
|
|
68
|
+
aria-selected={isActive}
|
|
69
|
+
tabindex={tabindex ?? (isActive ? 0 : -1)}
|
|
27
70
|
class={cn(
|
|
28
71
|
"inline-flex items-center justify-center gap-1.5 whitespace-nowrap rounded-md px-2.5 py-1 text-sm font-medium transition-all outline-none focus-visible:ring-2 focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-4 [&_svg]:shrink-0",
|
|
29
|
-
|
|
72
|
+
isActive
|
|
30
73
|
? "bg-background text-foreground shadow-sm"
|
|
31
74
|
: "text-muted-foreground hover:text-foreground",
|
|
32
75
|
className
|
|
33
76
|
)}
|
|
34
77
|
{...restProps}
|
|
78
|
+
onclick={handleClick}
|
|
79
|
+
onkeydown={handleKeydown}
|
|
35
80
|
>
|
|
36
81
|
{@render children?.()}
|
|
37
82
|
</button>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
/* eslint-disable no-useless-assignment */
|
|
3
2
|
import { cn, type WithElementRef } from "../../../utils.js";
|
|
4
3
|
import type { HTMLAttributes } from "svelte/elements";
|
|
4
|
+
import { setTabsContext } from "./tabs-context.svelte.js";
|
|
5
5
|
|
|
6
6
|
type Props = WithElementRef<HTMLAttributes<HTMLDivElement>> & {
|
|
7
7
|
value?: string;
|
|
@@ -16,6 +16,17 @@
|
|
|
16
16
|
children,
|
|
17
17
|
...restProps
|
|
18
18
|
}: Props = $props();
|
|
19
|
+
|
|
20
|
+
setTabsContext({
|
|
21
|
+
get value() {
|
|
22
|
+
return value;
|
|
23
|
+
},
|
|
24
|
+
select(nextValue) {
|
|
25
|
+
if (nextValue === value) return;
|
|
26
|
+
value = nextValue;
|
|
27
|
+
onValueChange?.(nextValue);
|
|
28
|
+
},
|
|
29
|
+
});
|
|
19
30
|
</script>
|
|
20
31
|
|
|
21
32
|
<div
|
|
@@ -3,4 +3,7 @@ import Trigger from "./tooltip-trigger.svelte";
|
|
|
3
3
|
import Content from "./tooltip-content.svelte";
|
|
4
4
|
import Provider from "./tooltip-provider.svelte";
|
|
5
5
|
import Portal from "./tooltip-portal.svelte";
|
|
6
|
-
|
|
6
|
+
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
|
7
|
+
declare const createTether: typeof TooltipPrimitive.createTether;
|
|
8
|
+
type Tether<Payload = never> = TooltipPrimitive.Tether<Payload>;
|
|
9
|
+
export { Root, Trigger, Content, Provider, Portal, createTether, type Tether, Root as Tooltip, Content as TooltipContent, Trigger as TooltipTrigger, Provider as TooltipProvider, Portal as TooltipPortal, };
|
|
@@ -3,6 +3,8 @@ import Trigger from "./tooltip-trigger.svelte";
|
|
|
3
3
|
import Content from "./tooltip-content.svelte";
|
|
4
4
|
import Provider from "./tooltip-provider.svelte";
|
|
5
5
|
import Portal from "./tooltip-portal.svelte";
|
|
6
|
-
|
|
6
|
+
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
|
7
|
+
const createTether = TooltipPrimitive.createTether;
|
|
8
|
+
export { Root, Trigger, Content, Provider, Portal, createTether,
|
|
7
9
|
//
|
|
8
10
|
Root as Tooltip, Content as TooltipContent, Trigger as TooltipTrigger, Provider as TooltipProvider, Portal as TooltipPortal, };
|
|
@@ -1,52 +1,325 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
arrow,
|
|
4
|
+
autoUpdate,
|
|
5
|
+
computePosition,
|
|
6
|
+
flip,
|
|
7
|
+
hide,
|
|
8
|
+
limitShift,
|
|
9
|
+
offset,
|
|
10
|
+
shift,
|
|
11
|
+
type Boundary,
|
|
12
|
+
type Padding,
|
|
13
|
+
type Placement,
|
|
14
|
+
type ReferenceElement,
|
|
15
|
+
type Strategy,
|
|
16
|
+
} from "@floating-ui/dom";
|
|
2
17
|
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
|
18
|
+
import { onDestroy, type ComponentProps, type Snippet } from "svelte";
|
|
19
|
+
import { createAttachmentKey } from "svelte/attachments";
|
|
20
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
3
21
|
import { cn } from "../../../utils.js";
|
|
22
|
+
import { getTooltipLayerContext } from "./tooltip-context.svelte.js";
|
|
23
|
+
import {
|
|
24
|
+
registerTooltipLayer,
|
|
25
|
+
type TooltipLayerBehavior,
|
|
26
|
+
} from "./tooltip-layer-registry.svelte.js";
|
|
4
27
|
import TooltipPortal from "./tooltip-portal.svelte";
|
|
5
|
-
import type { ComponentProps } from "svelte";
|
|
6
28
|
import type { WithoutChildrenOrChild } from "../../../utils.js";
|
|
7
29
|
|
|
30
|
+
type Side = "top" | "right" | "bottom" | "left";
|
|
31
|
+
type Align = "start" | "center" | "end";
|
|
32
|
+
type OutsideBehavior = TooltipLayerBehavior;
|
|
33
|
+
type EscapeBehavior = TooltipLayerBehavior;
|
|
34
|
+
type ContentPointerHandler = NonNullable<HTMLAttributes<HTMLDivElement>["onpointerenter"]>;
|
|
35
|
+
type ContentPointerEvent = Parameters<ContentPointerHandler>[0];
|
|
36
|
+
type TooltipContentChildProps = {
|
|
37
|
+
props: Record<PropertyKey, unknown>;
|
|
38
|
+
wrapperProps: Record<string, unknown>;
|
|
39
|
+
open: boolean;
|
|
40
|
+
};
|
|
41
|
+
type TooltipContentProps = Omit<
|
|
42
|
+
HTMLAttributes<HTMLDivElement>,
|
|
43
|
+
"children" | "class" | "id" | "style"
|
|
44
|
+
> & {
|
|
45
|
+
ref?: HTMLDivElement | null;
|
|
46
|
+
class?: string;
|
|
47
|
+
id?: string;
|
|
48
|
+
style?: TooltipPrimitive.ContentProps["style"];
|
|
49
|
+
dir?: TooltipPrimitive.ContentProps["dir"];
|
|
50
|
+
side?: Side;
|
|
51
|
+
sideOffset?: number;
|
|
52
|
+
align?: Align;
|
|
53
|
+
alignOffset?: number;
|
|
54
|
+
arrowPadding?: Padding;
|
|
55
|
+
avoidCollisions?: boolean;
|
|
56
|
+
collisionBoundary?: Boundary;
|
|
57
|
+
collisionPadding?: Padding;
|
|
58
|
+
customAnchor?: ReferenceElement | string | null;
|
|
59
|
+
sticky?: "partial" | "always";
|
|
60
|
+
strategy?: Strategy;
|
|
61
|
+
updatePositionStrategy?: "optimized" | "always";
|
|
62
|
+
hideWhenDetached?: boolean;
|
|
63
|
+
forceMount?: boolean;
|
|
64
|
+
onPlaced?: () => void;
|
|
65
|
+
onInteractOutside?: (event: PointerEvent) => void;
|
|
66
|
+
onFocusOutside?: (event: FocusEvent) => void;
|
|
67
|
+
interactOutsideBehavior?: OutsideBehavior;
|
|
68
|
+
onEscapeKeydown?: (event: KeyboardEvent) => void;
|
|
69
|
+
escapeKeydownBehavior?: EscapeBehavior;
|
|
70
|
+
children?: Snippet;
|
|
71
|
+
child?: Snippet<[TooltipContentChildProps]>;
|
|
72
|
+
arrowClasses?: string;
|
|
73
|
+
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof TooltipPortal>>;
|
|
74
|
+
};
|
|
75
|
+
|
|
8
76
|
let {
|
|
9
77
|
ref = $bindable(null),
|
|
10
78
|
class: className,
|
|
11
|
-
|
|
79
|
+
id,
|
|
80
|
+
style,
|
|
81
|
+
dir,
|
|
12
82
|
side = "top",
|
|
83
|
+
sideOffset = 0,
|
|
84
|
+
align = "center",
|
|
85
|
+
alignOffset = 0,
|
|
86
|
+
arrowPadding = 0,
|
|
87
|
+
avoidCollisions = true,
|
|
88
|
+
collisionBoundary,
|
|
89
|
+
collisionPadding = 0,
|
|
90
|
+
customAnchor,
|
|
91
|
+
sticky = "partial",
|
|
92
|
+
strategy = "fixed",
|
|
93
|
+
updatePositionStrategy = "optimized",
|
|
94
|
+
hideWhenDetached = false,
|
|
95
|
+
forceMount = false,
|
|
96
|
+
onPlaced,
|
|
97
|
+
onInteractOutside,
|
|
98
|
+
onFocusOutside,
|
|
99
|
+
interactOutsideBehavior = "close",
|
|
100
|
+
onEscapeKeydown,
|
|
101
|
+
escapeKeydownBehavior = "close",
|
|
102
|
+
onpointerenter,
|
|
103
|
+
onpointerleave,
|
|
13
104
|
children,
|
|
105
|
+
child,
|
|
14
106
|
arrowClasses,
|
|
15
107
|
portalProps,
|
|
16
|
-
...
|
|
17
|
-
}:
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
108
|
+
...domProps
|
|
109
|
+
}: TooltipContentProps = $props();
|
|
110
|
+
|
|
111
|
+
const tooltip = getTooltipLayerContext();
|
|
112
|
+
const unregisterContentId = tooltip.registerContentId(() => id ?? tooltip.defaultContentId);
|
|
113
|
+
let x = $state(-10_000);
|
|
114
|
+
let y = $state(-10_000);
|
|
115
|
+
let resolvedSide = $state<Side>("top");
|
|
116
|
+
let arrowX = $state<number | undefined>();
|
|
117
|
+
let arrowY = $state<number | undefined>();
|
|
118
|
+
let arrowStaticSide = $state<Side>("bottom");
|
|
119
|
+
let referenceHidden = $state(false);
|
|
120
|
+
let positioned = $state(false);
|
|
121
|
+
let arrowRef: HTMLDivElement | null = $state(null);
|
|
122
|
+
let destroyed = false;
|
|
123
|
+
let positionGeneration = 0;
|
|
124
|
+
const contentAttachmentKey = createAttachmentKey();
|
|
22
125
|
|
|
23
|
-
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
126
|
+
const contentId = $derived(id ?? tooltip.defaultContentId);
|
|
127
|
+
const placement = $derived<Placement>(align === "center" ? side : `${side}-${align}`);
|
|
128
|
+
const arrowStyle = $derived(
|
|
129
|
+
[
|
|
130
|
+
arrowX === undefined ? undefined : `left: ${arrowX}px`,
|
|
131
|
+
arrowY === undefined ? undefined : `top: ${arrowY}px`,
|
|
132
|
+
`${arrowStaticSide}: -5px`,
|
|
133
|
+
]
|
|
134
|
+
.filter(Boolean)
|
|
135
|
+
.join("; ")
|
|
136
|
+
);
|
|
137
|
+
const contentClass = $derived(
|
|
138
|
+
cn(
|
|
139
|
+
"animate-in fade-in-0 zoom-in-95 inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs has-data-[slot=kbd]:pr-1.5 **:data-[slot=kbd]:relative **:data-[slot=kbd]:isolate **:data-[slot=kbd]:z-50 **:data-[slot=kbd]:rounded-sm bg-primary text-primary-foreground z-50 w-fit max-w-xs",
|
|
31
140
|
className
|
|
32
|
-
)
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
141
|
+
)
|
|
142
|
+
);
|
|
143
|
+
function serializeStyle(value: TooltipPrimitive.ContentProps["style"]) {
|
|
144
|
+
if (!value) return "";
|
|
145
|
+
if (typeof value === "string") return value.trim().replace(/;$/, "");
|
|
146
|
+
return Object.entries(value)
|
|
147
|
+
.filter(([, propertyValue]) => propertyValue !== null && propertyValue !== undefined)
|
|
148
|
+
.map(([property, propertyValue]) => {
|
|
149
|
+
const cssProperty = property.startsWith("--")
|
|
150
|
+
? property
|
|
151
|
+
: property.replace(/[A-Z]/g, (match) => `-${match.toLowerCase()}`);
|
|
152
|
+
return `${cssProperty}: ${String(propertyValue)}`;
|
|
153
|
+
})
|
|
154
|
+
.join("; ");
|
|
155
|
+
}
|
|
156
|
+
const contentStyle = $derived(
|
|
157
|
+
[
|
|
158
|
+
serializeStyle(style),
|
|
159
|
+
`position: ${strategy}`,
|
|
160
|
+
`left: ${x}px`,
|
|
161
|
+
`top: ${y}px`,
|
|
162
|
+
`visibility: ${(tooltip.open || tooltip.presenceStatus === "ending") && positioned && !referenceHidden ? "visible" : "hidden"}`,
|
|
163
|
+
`pointer-events: ${tooltip.open && !tooltip.disableHoverableContent ? "auto" : "none"}`,
|
|
164
|
+
]
|
|
165
|
+
.filter(Boolean)
|
|
166
|
+
.join("; ")
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
function attachContent(node: HTMLDivElement) {
|
|
170
|
+
ref = node;
|
|
171
|
+
tooltip.setContentNode(node);
|
|
172
|
+
return () => {
|
|
173
|
+
if (ref === node) ref = null;
|
|
174
|
+
tooltip.setContentNode(null);
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const contentProps = $derived.by(
|
|
179
|
+
() =>
|
|
180
|
+
({
|
|
181
|
+
...domProps,
|
|
182
|
+
[contentAttachmentKey]: attachContent,
|
|
183
|
+
id: contentId,
|
|
184
|
+
role: "tooltip",
|
|
185
|
+
"data-slot": "tooltip-content",
|
|
186
|
+
"data-state": tooltip.open ? "instant-open" : "closed",
|
|
187
|
+
"data-starting-style": tooltip.presenceStatus === "starting" ? "" : undefined,
|
|
188
|
+
"data-ending-style": tooltip.presenceStatus === "ending" ? "" : undefined,
|
|
189
|
+
"data-side": resolvedSide,
|
|
190
|
+
"aria-hidden": !tooltip.open,
|
|
191
|
+
dir,
|
|
192
|
+
style: contentStyle,
|
|
193
|
+
class: contentClass,
|
|
194
|
+
onpointerenter: handlePointerEnter,
|
|
195
|
+
onpointerleave: handlePointerLeave,
|
|
196
|
+
}) satisfies Record<PropertyKey, unknown>
|
|
197
|
+
);
|
|
198
|
+
const wrapperProps = $derived({ style: "display: contents" });
|
|
199
|
+
|
|
200
|
+
function getAnchor(): ReferenceElement | null {
|
|
201
|
+
if (typeof customAnchor === "string") return document.querySelector(customAnchor);
|
|
202
|
+
return customAnchor ?? tooltip.trigger;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function handlePointerEnter(event: ContentPointerEvent) {
|
|
206
|
+
tooltip.cancelScheduledClose();
|
|
207
|
+
onpointerenter?.(event);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function handlePointerLeave(event: ContentPointerEvent) {
|
|
211
|
+
onpointerleave?.(event);
|
|
212
|
+
if (!event.defaultPrevented) tooltip.scheduleClose();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
$effect(() => {
|
|
216
|
+
const anchor = getAnchor();
|
|
217
|
+
const floating = ref;
|
|
218
|
+
const arrowElement = arrowRef;
|
|
219
|
+
if (!tooltip.open || !anchor || !floating || destroyed) return;
|
|
220
|
+
|
|
221
|
+
let active = true;
|
|
222
|
+
positioned = false;
|
|
223
|
+
const update = async () => {
|
|
224
|
+
const generation = ++positionGeneration;
|
|
225
|
+
const result = await computePosition(anchor, floating, {
|
|
226
|
+
placement,
|
|
227
|
+
strategy,
|
|
228
|
+
middleware: [
|
|
229
|
+
offset({ mainAxis: sideOffset, alignmentAxis: alignOffset || undefined }),
|
|
230
|
+
avoidCollisions && flip({ boundary: collisionBoundary, padding: collisionPadding }),
|
|
231
|
+
avoidCollisions &&
|
|
232
|
+
shift({
|
|
233
|
+
boundary: collisionBoundary,
|
|
234
|
+
padding: collisionPadding,
|
|
235
|
+
limiter: sticky === "partial" ? limitShift() : undefined,
|
|
236
|
+
}),
|
|
237
|
+
arrowElement && arrow({ element: arrowElement, padding: arrowPadding }),
|
|
238
|
+
hideWhenDetached && hide({ boundary: collisionBoundary, padding: collisionPadding }),
|
|
239
|
+
],
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
if (
|
|
243
|
+
!active ||
|
|
244
|
+
destroyed ||
|
|
245
|
+
generation !== positionGeneration ||
|
|
246
|
+
ref !== floating ||
|
|
247
|
+
!tooltip.open
|
|
248
|
+
) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
x = result.x;
|
|
253
|
+
y = result.y;
|
|
254
|
+
resolvedSide = result.placement.split("-")[0] as Side;
|
|
255
|
+
arrowX = result.middlewareData.arrow?.x;
|
|
256
|
+
arrowY = result.middlewareData.arrow?.y;
|
|
257
|
+
arrowStaticSide = {
|
|
258
|
+
top: "bottom",
|
|
259
|
+
right: "left",
|
|
260
|
+
bottom: "top",
|
|
261
|
+
left: "right",
|
|
262
|
+
}[resolvedSide] as Side;
|
|
263
|
+
referenceHidden = Boolean(result.middlewareData.hide?.referenceHidden);
|
|
264
|
+
positioned = true;
|
|
265
|
+
onPlaced?.();
|
|
266
|
+
};
|
|
267
|
+
|
|
268
|
+
const stopAutoUpdate = autoUpdate(anchor, floating, () => void update(), {
|
|
269
|
+
animationFrame: updatePositionStrategy === "always",
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
return () => {
|
|
273
|
+
active = false;
|
|
274
|
+
positionGeneration += 1;
|
|
275
|
+
stopAutoUpdate();
|
|
276
|
+
};
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
$effect(() => {
|
|
280
|
+
const floating = ref;
|
|
281
|
+
if (!tooltip.open || !floating || destroyed) return;
|
|
282
|
+
|
|
283
|
+
const ownerDocument = floating.ownerDocument;
|
|
284
|
+
const NodeConstructor = ownerDocument.defaultView?.Node;
|
|
285
|
+
return registerTooltipLayer(ownerDocument, {
|
|
286
|
+
containsTarget: (target) => {
|
|
287
|
+
if (!NodeConstructor || !(target instanceof NodeConstructor)) return false;
|
|
288
|
+
return floating.contains(target) || Boolean(tooltip.trigger?.contains(target));
|
|
289
|
+
},
|
|
290
|
+
getInteractOutsideBehavior: () => interactOutsideBehavior,
|
|
291
|
+
getEscapeKeydownBehavior: () => escapeKeydownBehavior,
|
|
292
|
+
onInteractOutside: (event) => onInteractOutside?.(event),
|
|
293
|
+
onFocusOutside: (event) => onFocusOutside?.(event),
|
|
294
|
+
onEscapeKeydown: (event) => onEscapeKeydown?.(event),
|
|
295
|
+
close: () => tooltip.close(),
|
|
296
|
+
});
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
onDestroy(() => {
|
|
300
|
+
destroyed = true;
|
|
301
|
+
positionGeneration += 1;
|
|
302
|
+
unregisterContentId();
|
|
303
|
+
ref = null;
|
|
304
|
+
arrowRef = null;
|
|
305
|
+
});
|
|
306
|
+
</script>
|
|
307
|
+
|
|
308
|
+
{#if tooltip.shouldRender || forceMount}
|
|
309
|
+
<TooltipPortal {...portalProps}>
|
|
310
|
+
{#if child}
|
|
311
|
+
{@render child({ props: contentProps, wrapperProps, open: tooltip.open })}
|
|
312
|
+
{:else}
|
|
313
|
+
<div {...contentProps}>
|
|
314
|
+
{@render children?.()}
|
|
38
315
|
<div
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"data-[side=left]:-translate-y-[calc(50%-3px)]",
|
|
45
|
-
arrowClasses
|
|
46
|
-
)}
|
|
47
|
-
{...props}
|
|
316
|
+
bind:this={arrowRef}
|
|
317
|
+
aria-hidden="true"
|
|
318
|
+
data-side={resolvedSide}
|
|
319
|
+
style={arrowStyle}
|
|
320
|
+
class={cn("absolute size-2.5 rotate-45 rounded-[2px] bg-primary -z-10", arrowClasses)}
|
|
48
321
|
></div>
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
</
|
|
52
|
-
|
|
322
|
+
</div>
|
|
323
|
+
{/if}
|
|
324
|
+
</TooltipPortal>
|
|
325
|
+
{/if}
|
|
@@ -1,11 +1,50 @@
|
|
|
1
|
+
import { type Boundary, type Padding, type ReferenceElement, type Strategy } from "@floating-ui/dom";
|
|
1
2
|
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
|
3
|
+
import { type ComponentProps, type Snippet } from "svelte";
|
|
4
|
+
import type { HTMLAttributes } from "svelte/elements";
|
|
5
|
+
import { type TooltipLayerBehavior } from "./tooltip-layer-registry.svelte.js";
|
|
2
6
|
import TooltipPortal from "./tooltip-portal.svelte";
|
|
3
|
-
import type { ComponentProps } from "svelte";
|
|
4
7
|
import type { WithoutChildrenOrChild } from "../../../utils.js";
|
|
5
|
-
type
|
|
8
|
+
type Side = "top" | "right" | "bottom" | "left";
|
|
9
|
+
type Align = "start" | "center" | "end";
|
|
10
|
+
type OutsideBehavior = TooltipLayerBehavior;
|
|
11
|
+
type EscapeBehavior = TooltipLayerBehavior;
|
|
12
|
+
type TooltipContentChildProps = {
|
|
13
|
+
props: Record<PropertyKey, unknown>;
|
|
14
|
+
wrapperProps: Record<string, unknown>;
|
|
15
|
+
open: boolean;
|
|
16
|
+
};
|
|
17
|
+
type TooltipContentProps = Omit<HTMLAttributes<HTMLDivElement>, "children" | "class" | "id" | "style"> & {
|
|
18
|
+
ref?: HTMLDivElement | null;
|
|
19
|
+
class?: string;
|
|
20
|
+
id?: string;
|
|
21
|
+
style?: TooltipPrimitive.ContentProps["style"];
|
|
22
|
+
dir?: TooltipPrimitive.ContentProps["dir"];
|
|
23
|
+
side?: Side;
|
|
24
|
+
sideOffset?: number;
|
|
25
|
+
align?: Align;
|
|
26
|
+
alignOffset?: number;
|
|
27
|
+
arrowPadding?: Padding;
|
|
28
|
+
avoidCollisions?: boolean;
|
|
29
|
+
collisionBoundary?: Boundary;
|
|
30
|
+
collisionPadding?: Padding;
|
|
31
|
+
customAnchor?: ReferenceElement | string | null;
|
|
32
|
+
sticky?: "partial" | "always";
|
|
33
|
+
strategy?: Strategy;
|
|
34
|
+
updatePositionStrategy?: "optimized" | "always";
|
|
35
|
+
hideWhenDetached?: boolean;
|
|
36
|
+
forceMount?: boolean;
|
|
37
|
+
onPlaced?: () => void;
|
|
38
|
+
onInteractOutside?: (event: PointerEvent) => void;
|
|
39
|
+
onFocusOutside?: (event: FocusEvent) => void;
|
|
40
|
+
interactOutsideBehavior?: OutsideBehavior;
|
|
41
|
+
onEscapeKeydown?: (event: KeyboardEvent) => void;
|
|
42
|
+
escapeKeydownBehavior?: EscapeBehavior;
|
|
43
|
+
children?: Snippet;
|
|
44
|
+
child?: Snippet<[TooltipContentChildProps]>;
|
|
6
45
|
arrowClasses?: string;
|
|
7
46
|
portalProps?: WithoutChildrenOrChild<ComponentProps<typeof TooltipPortal>>;
|
|
8
47
|
};
|
|
9
|
-
declare const TooltipContent: import("svelte").Component
|
|
48
|
+
declare const TooltipContent: import("svelte").Component<TooltipContentProps, {}, "ref">;
|
|
10
49
|
type TooltipContent = ReturnType<typeof TooltipContent>;
|
|
11
50
|
export default TooltipContent;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Tooltip as TooltipPrimitive } from 'bits-ui';
|
|
2
|
+
type TriggerReader = () => HTMLElement | null;
|
|
3
|
+
type ContentIdReader = () => string;
|
|
4
|
+
type TooltipTether = TooltipPrimitive.Tether<unknown>;
|
|
5
|
+
type PresenceStatus = 'starting' | 'ending' | undefined;
|
|
6
|
+
export declare class TooltipLayerContext {
|
|
7
|
+
#private;
|
|
8
|
+
readonly defaultContentId: string;
|
|
9
|
+
shouldRender: boolean;
|
|
10
|
+
presenceStatus: PresenceStatus;
|
|
11
|
+
constructor(defaultContentId: string, readOpen: () => boolean, writeOpen: (open: boolean) => void, readDisableHoverableContent: () => boolean, readActiveTriggerId: () => string | null, readExternalTrigger?: (triggerId: string) => HTMLElement | null, readOnOpenChangeComplete?: () => ((open: boolean) => void) | undefined);
|
|
12
|
+
get open(): boolean;
|
|
13
|
+
get trigger(): HTMLElement | null;
|
|
14
|
+
get activeTriggerId(): string | null;
|
|
15
|
+
get contentId(): string;
|
|
16
|
+
get disableHoverableContent(): boolean;
|
|
17
|
+
close(): void;
|
|
18
|
+
scheduleClose(delay?: number): void;
|
|
19
|
+
cancelScheduledClose(): void;
|
|
20
|
+
destroy(): void;
|
|
21
|
+
setContentNode(node: HTMLElement | null): void;
|
|
22
|
+
transitionPresence(open: boolean): void;
|
|
23
|
+
registerTrigger(triggerId: string, readTrigger: TriggerReader): () => void;
|
|
24
|
+
isActiveTrigger(triggerId: string): boolean;
|
|
25
|
+
registerContentId(readContentId: ContentIdReader): () => void;
|
|
26
|
+
}
|
|
27
|
+
export declare const getTooltipLayerContext: () => TooltipLayerContext, setTooltipLayerContext: (context: TooltipLayerContext) => TooltipLayerContext;
|
|
28
|
+
export declare function tryGetTooltipLayerContext(): TooltipLayerContext | undefined;
|
|
29
|
+
export declare class TooltipTetherBridge {
|
|
30
|
+
#private;
|
|
31
|
+
layer: TooltipLayerContext | null;
|
|
32
|
+
registerLayer(layer: TooltipLayerContext): () => void;
|
|
33
|
+
registerTrigger(triggerId: string, readTrigger: TriggerReader): () => void;
|
|
34
|
+
getTrigger(triggerId: string): HTMLElement | null;
|
|
35
|
+
}
|
|
36
|
+
export declare function getTooltipTetherBridge(tether: TooltipTether): TooltipTetherBridge;
|
|
37
|
+
export {};
|