@pzerelles/headlessui-svelte 2.1.2-next.19 → 2.1.2-next.20
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/hooks/use-event-listener.svelte.d.ts +1 -1
- package/dist/hooks/use-event-listener.svelte.js +3 -1
- package/dist/hooks/use-root-containers.svelte.d.ts +2 -2
- package/dist/hooks/use-root-containers.svelte.js +5 -5
- package/dist/hooks/use-tab-direction.svelte.js +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/internal/floating-provider.svelte.js +14 -14
- package/dist/internal/floating.svelte.js +1 -0
- package/dist/popover/Popover.svelte +161 -0
- package/dist/popover/Popover.svelte.d.ts +41 -0
- package/dist/popover/PopoverBackdrop.svelte +56 -0
- package/dist/popover/PopoverBackdrop.svelte.d.ts +45 -0
- package/dist/popover/PopoverButton.svelte +246 -0
- package/dist/popover/PopoverButton.svelte.d.ts +46 -0
- package/dist/popover/PopoverGroup.svelte +43 -0
- package/dist/popover/PopoverGroup.svelte.d.ts +33 -0
- package/dist/popover/PopoverPanel.svelte +274 -0
- package/dist/popover/PopoverPanel.svelte.d.ts +53 -0
- package/dist/popover/context.svelte.d.ts +51 -0
- package/dist/popover/context.svelte.js +108 -0
- package/dist/popover/index.d.ts +5 -0
- package/dist/popover/index.js +5 -0
- package/package.json +15 -15
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare function useEventListener<TType extends keyof WindowEventMap>(params: {
|
|
2
2
|
element: HTMLElement | Document | Window | EventTarget | null | undefined;
|
|
3
3
|
type: TType;
|
|
4
|
-
listener: (event: WindowEventMap[TType]) =>
|
|
4
|
+
listener: (event: WindowEventMap[TType]) => unknown;
|
|
5
5
|
options?: boolean | AddEventListenerOptions;
|
|
6
6
|
}): void;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export function useEventListener(params) {
|
|
2
|
-
|
|
2
|
+
if (typeof window === "undefined")
|
|
3
|
+
return;
|
|
4
|
+
const { element = window, type, listener, options } = $derived(params);
|
|
3
5
|
$effect(() => {
|
|
4
6
|
if (!element)
|
|
5
7
|
return;
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
export { default as MainTreeProvider, useMainTreeNode } from "../internal/MainTreeProvider.svelte";
|
|
2
2
|
export declare function useRootContainers(options?: {
|
|
3
|
-
defaultContainers?: (HTMLElement | null)[];
|
|
3
|
+
defaultContainers?: (HTMLElement | undefined | null)[];
|
|
4
4
|
portals?: HTMLElement[];
|
|
5
|
-
mainTreeNode?: HTMLElement | null;
|
|
5
|
+
mainTreeNode?: HTMLElement | undefined | null;
|
|
6
6
|
}): {
|
|
7
7
|
readonly resolvedContainers: HTMLElement[];
|
|
8
8
|
contains: (element: HTMLElement) => boolean;
|
|
@@ -6,21 +6,21 @@ export function useRootContainers(options = {}) {
|
|
|
6
6
|
mainTreeNode, } = $derived(options);
|
|
7
7
|
const ownerDocument = $derived(getOwnerDocument(mainTreeNode));
|
|
8
8
|
const resolvedContainers = $derived.by(() => {
|
|
9
|
-
|
|
9
|
+
const containers = [];
|
|
10
10
|
// Resolve default containers
|
|
11
|
-
for (
|
|
12
|
-
if (container
|
|
11
|
+
for (const container of defaultContainers) {
|
|
12
|
+
if (!container)
|
|
13
13
|
continue;
|
|
14
14
|
containers.push(container);
|
|
15
15
|
}
|
|
16
16
|
// Resolve portal containers
|
|
17
17
|
if (portals) {
|
|
18
|
-
for (
|
|
18
|
+
for (const portal of portals) {
|
|
19
19
|
containers.push(portal);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
// Resolve third party (root) containers
|
|
23
|
-
for (
|
|
23
|
+
for (const container of ownerDocument?.querySelectorAll("html > *, body > *") ?? []) {
|
|
24
24
|
if (container === document.body)
|
|
25
25
|
continue; // Skip `<body>`
|
|
26
26
|
if (container === document.head)
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./label/index.js";
|
|
|
11
11
|
export * from "./legend/index.js";
|
|
12
12
|
export * from "./listbox/index.js";
|
|
13
13
|
export * from "./menu/index.js";
|
|
14
|
+
export * from "./popover/index.js";
|
|
14
15
|
export * from "./select/index.js";
|
|
15
16
|
export * from "./switch/index.js";
|
|
16
17
|
export * from "./tabs/index.js";
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ export * from "./label/index.js";
|
|
|
11
11
|
export * from "./legend/index.js";
|
|
12
12
|
export * from "./listbox/index.js";
|
|
13
13
|
export * from "./menu/index.js";
|
|
14
|
+
export * from "./popover/index.js";
|
|
14
15
|
export * from "./select/index.js";
|
|
15
16
|
export * from "./switch/index.js";
|
|
16
17
|
export * from "./tabs/index.js";
|
|
@@ -4,11 +4,11 @@ import { autoUpdate, flip as flipMiddleware, inner as innerMiddleware, offset as
|
|
|
4
4
|
export const useFloatingProvider = (options = { enabled: true }) => {
|
|
5
5
|
const { enabled } = $derived(options);
|
|
6
6
|
// TODO: Make this a config part of the `config`. Just need to decide on a name.
|
|
7
|
-
|
|
7
|
+
const MINIMUM_ITEMS_VISIBLE = 4;
|
|
8
8
|
let config = $state(null);
|
|
9
9
|
let innerOffset = $state(0);
|
|
10
10
|
const setInnerOffset = (offset) => (innerOffset = typeof offset === "function" ? offset(innerOffset) : offset);
|
|
11
|
-
|
|
11
|
+
const overflowRef = $state({ current: null });
|
|
12
12
|
let floatingEl = $state(null);
|
|
13
13
|
const setFloatingElement = (element) => (floatingEl = element);
|
|
14
14
|
useFixScrollingPixel({
|
|
@@ -26,7 +26,7 @@ export const useFloatingProvider = (options = { enabled: true }) => {
|
|
|
26
26
|
},
|
|
27
27
|
});
|
|
28
28
|
const { to: placement = "bottom", gap = 0, offset = 0, padding = 0, inner } = $derived(resolvedConfig);
|
|
29
|
-
|
|
29
|
+
const [to, align = "center"] = $derived(placement.split(" "));
|
|
30
30
|
// Reset
|
|
31
31
|
$effect(() => {
|
|
32
32
|
if (!isEnabled)
|
|
@@ -65,24 +65,24 @@ export const useFloatingProvider = (options = { enabled: true }) => {
|
|
|
65
65
|
onFallbackChange(fallback) {
|
|
66
66
|
if (!fallback)
|
|
67
67
|
return;
|
|
68
|
-
|
|
68
|
+
const parent = context.elements.floating;
|
|
69
69
|
if (!parent)
|
|
70
70
|
return;
|
|
71
|
-
|
|
71
|
+
const scrollPaddingBottom = parseFloat(getComputedStyle(parent).scrollPaddingBottom) || 0;
|
|
72
72
|
// We want at least X visible items, but if there are less than X items in the list,
|
|
73
73
|
// we want to show as many as possible.
|
|
74
74
|
let missing = Math.min(MINIMUM_ITEMS_VISIBLE, parent.childElementCount);
|
|
75
75
|
let elementHeight = 0;
|
|
76
76
|
let elementAmountVisible = 0;
|
|
77
|
-
for (
|
|
77
|
+
for (const child of context.elements.floating?.childNodes ?? []) {
|
|
78
78
|
if (child instanceof HTMLElement) {
|
|
79
|
-
|
|
79
|
+
const childTop = child.offsetTop;
|
|
80
80
|
// It can be that the child is fully visible, but we also want to keep the scroll
|
|
81
81
|
// padding into account to ensure the UI looks good. Therefore we fake that the
|
|
82
82
|
// bottom of the child is actually `scrollPaddingBottom` amount of pixels lower.
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
const childBottom = childTop + child.clientHeight + scrollPaddingBottom;
|
|
84
|
+
const parentTop = parent.scrollTop;
|
|
85
|
+
const parentBottom = parentTop + parent.clientHeight;
|
|
86
86
|
// Figure out if the child is fully visible in the scroll parent.
|
|
87
87
|
if (childTop >= parentTop && childBottom <= parentBottom) {
|
|
88
88
|
missing--;
|
|
@@ -101,7 +101,7 @@ export const useFloatingProvider = (options = { enabled: true }) => {
|
|
|
101
101
|
// to show more items.
|
|
102
102
|
if (missing >= 1) {
|
|
103
103
|
setInnerOffset((existingOffset) => {
|
|
104
|
-
|
|
104
|
+
const newInnerOffset = elementHeight * missing - // `missing` amount of `elementHeight`
|
|
105
105
|
elementAmountVisible + // The amount of the last item that is visible
|
|
106
106
|
scrollPaddingBottom; // The scroll padding to ensure the UI looks good
|
|
107
107
|
// Nudged enough already, no need to continue
|
|
@@ -154,7 +154,7 @@ export const useFloatingProvider = (options = { enabled: true }) => {
|
|
|
154
154
|
const { refs, floatingStyles, context } = $derived(floating);
|
|
155
155
|
// Calculate placement information to expose as data attributes
|
|
156
156
|
const { exposedTo, exposedAlign } = $derived.by(() => {
|
|
157
|
-
|
|
157
|
+
const [exposedTo = to, exposedAlign = align] = context.placement.split("-");
|
|
158
158
|
return { exposedTo: to === "selection" ? "selection" : exposedTo, exposedAlign };
|
|
159
159
|
});
|
|
160
160
|
// If user-land code is using custom styles specifically for `bottom`, but
|
|
@@ -164,7 +164,7 @@ export const useFloatingProvider = (options = { enabled: true }) => {
|
|
|
164
164
|
const data = $derived({
|
|
165
165
|
anchor: [exposedTo, exposedAlign].filter(Boolean).join(" "),
|
|
166
166
|
});
|
|
167
|
-
|
|
167
|
+
const innerOffsetConfig = useInnerOffset({
|
|
168
168
|
get context() {
|
|
169
169
|
return context;
|
|
170
170
|
},
|
|
@@ -175,7 +175,7 @@ export const useFloatingProvider = (options = { enabled: true }) => {
|
|
|
175
175
|
};
|
|
176
176
|
},
|
|
177
177
|
});
|
|
178
|
-
|
|
178
|
+
const { getReferenceProps, getFloatingProps } = useInteractions({
|
|
179
179
|
get propsList() {
|
|
180
180
|
return [innerOffsetConfig];
|
|
181
181
|
},
|
|
@@ -58,6 +58,7 @@ export function useFloatingPanel(options = { placement: null }) {
|
|
|
58
58
|
}
|
|
59
59
|
: undefined));
|
|
60
60
|
const stablePlacement = $derived.by(() => {
|
|
61
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
61
62
|
trigger;
|
|
62
63
|
return untrack(() => placement);
|
|
63
64
|
});
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
<script lang="ts" module>export const DEFAULT_POPOVER_TAG = "div";
|
|
2
|
+
</script>
|
|
3
|
+
|
|
4
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_POPOVER_TAG">import { getOwnerDocument } from "../utils/owner.js";
|
|
5
|
+
import { setContext, untrack } from "svelte";
|
|
6
|
+
import {
|
|
7
|
+
createPopoverContext,
|
|
8
|
+
PopoverStates,
|
|
9
|
+
usePopoverGroupContext
|
|
10
|
+
} from "./context.svelte.js";
|
|
11
|
+
import { FocusableMode, getFocusableElements, isFocusableElement } from "../utils/focus-management.js";
|
|
12
|
+
import { useNestedPortals } from "../portal/InternalPortal.svelte";
|
|
13
|
+
import MainTreeProvider, { useMainTreeNode } from "../internal/MainTreeProvider.svelte";
|
|
14
|
+
import { useRootContainers } from "../hooks/use-root-containers.svelte.js";
|
|
15
|
+
import { useEventListener } from "../hooks/use-event-listener.svelte.js";
|
|
16
|
+
import { useOutsideClick } from "../hooks/use-outside-click.svelte.js";
|
|
17
|
+
import { useFloatingProvider } from "../internal/floating-provider.svelte.js";
|
|
18
|
+
import { createCloseContext } from "../internal/close-provider.js";
|
|
19
|
+
import { createOpenClosedContext, State } from "../internal/open-closed.js";
|
|
20
|
+
import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
21
|
+
let { ref = $bindable(), __demoMode = false, ...theirProps } = $props();
|
|
22
|
+
let buttons = $state([]);
|
|
23
|
+
const context = createPopoverContext({
|
|
24
|
+
__demoMode,
|
|
25
|
+
popoverState: __demoMode ? PopoverStates.Open : PopoverStates.Closed,
|
|
26
|
+
buttons
|
|
27
|
+
});
|
|
28
|
+
const {
|
|
29
|
+
popoverState,
|
|
30
|
+
button,
|
|
31
|
+
buttonId,
|
|
32
|
+
panel,
|
|
33
|
+
panelId,
|
|
34
|
+
beforePanelSentinel,
|
|
35
|
+
afterPanelSentinel,
|
|
36
|
+
afterButtonSentinel
|
|
37
|
+
} = $derived(context);
|
|
38
|
+
const ownerDocument = $derived(getOwnerDocument(ref ?? button));
|
|
39
|
+
const isPortalled = $derived.by(() => {
|
|
40
|
+
if (!button) return false;
|
|
41
|
+
if (!panel) return false;
|
|
42
|
+
return untrack(() => {
|
|
43
|
+
for (let root2 of document.querySelectorAll("body > *")) {
|
|
44
|
+
if (Number(root2?.contains(button)) ^ Number(root2?.contains(panel))) {
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
let elements = getFocusableElements();
|
|
49
|
+
let buttonIdx = elements.indexOf(button);
|
|
50
|
+
let beforeIdx = (buttonIdx + elements.length - 1) % elements.length;
|
|
51
|
+
let afterIdx = (buttonIdx + 1) % elements.length;
|
|
52
|
+
let beforeElement = elements[beforeIdx];
|
|
53
|
+
let afterElement = elements[afterIdx];
|
|
54
|
+
if (!panel.contains(beforeElement) && !panel.contains(afterElement)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
return false;
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
const registerBag = $derived({
|
|
61
|
+
buttonId,
|
|
62
|
+
panelId,
|
|
63
|
+
close: () => context.closePopover()
|
|
64
|
+
});
|
|
65
|
+
const groupContext = usePopoverGroupContext();
|
|
66
|
+
const registerPopover = $derived(groupContext?.registerPopover);
|
|
67
|
+
const isFocusWithinPopoverGroup = () => {
|
|
68
|
+
return groupContext?.isFocusWithinPopoverGroup() ?? (ownerDocument?.activeElement && (button?.contains(ownerDocument.activeElement) || panel?.contains(ownerDocument.activeElement)));
|
|
69
|
+
};
|
|
70
|
+
$effect(() => registerPopover?.(registerBag));
|
|
71
|
+
const nestedPortals = useNestedPortals();
|
|
72
|
+
const { portals } = $derived(nestedPortals);
|
|
73
|
+
const mainTreeNode = useMainTreeNode({
|
|
74
|
+
get fallbackMainTreeNode() {
|
|
75
|
+
return button;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
const root = useRootContainers({
|
|
79
|
+
get mainTreeNode() {
|
|
80
|
+
return mainTreeNode.node;
|
|
81
|
+
},
|
|
82
|
+
get portals() {
|
|
83
|
+
return portals;
|
|
84
|
+
},
|
|
85
|
+
get defaultContainers() {
|
|
86
|
+
return [button, panel];
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
useEventListener({
|
|
90
|
+
get element() {
|
|
91
|
+
return ownerDocument?.defaultView;
|
|
92
|
+
},
|
|
93
|
+
type: "focus",
|
|
94
|
+
listener: (event) => {
|
|
95
|
+
if (event.target === window) return;
|
|
96
|
+
if (!(event.target instanceof HTMLElement)) return;
|
|
97
|
+
if (popoverState !== PopoverStates.Open) return;
|
|
98
|
+
if (isFocusWithinPopoverGroup()) return;
|
|
99
|
+
if (!button) return;
|
|
100
|
+
if (!panel) return;
|
|
101
|
+
if (root.contains(event.target)) return;
|
|
102
|
+
if (beforePanelSentinel?.contains?.(event.target)) return;
|
|
103
|
+
if (afterPanelSentinel?.contains?.(event.target)) return;
|
|
104
|
+
if (afterButtonSentinel?.contains?.(event.target)) return;
|
|
105
|
+
context.closePopover();
|
|
106
|
+
},
|
|
107
|
+
options: true
|
|
108
|
+
});
|
|
109
|
+
const outsideClickEnabled = $derived(popoverState === PopoverStates.Open);
|
|
110
|
+
useOutsideClick({
|
|
111
|
+
get enabled() {
|
|
112
|
+
return outsideClickEnabled;
|
|
113
|
+
},
|
|
114
|
+
get containers() {
|
|
115
|
+
return root.resolvedContainers;
|
|
116
|
+
},
|
|
117
|
+
cb: (event, target) => {
|
|
118
|
+
context.closePopover();
|
|
119
|
+
if (!isFocusableElement(target, FocusableMode.Loose)) {
|
|
120
|
+
event.preventDefault();
|
|
121
|
+
button?.focus();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
const close = (focusableElement) => {
|
|
126
|
+
context.closePopover();
|
|
127
|
+
const restoreElement = (() => {
|
|
128
|
+
if (!focusableElement) return button;
|
|
129
|
+
if (focusableElement instanceof HTMLElement) return focusableElement;
|
|
130
|
+
return button;
|
|
131
|
+
})();
|
|
132
|
+
restoreElement?.focus();
|
|
133
|
+
};
|
|
134
|
+
const api = {
|
|
135
|
+
close,
|
|
136
|
+
get isPortalled() {
|
|
137
|
+
return isPortalled;
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
setContext("PopoverAPIContext", api);
|
|
141
|
+
const slot = $derived({
|
|
142
|
+
open: popoverState === PopoverStates.Open,
|
|
143
|
+
close
|
|
144
|
+
});
|
|
145
|
+
useFloatingProvider();
|
|
146
|
+
setContext("PopoverPanelContext", void 0);
|
|
147
|
+
createCloseContext({
|
|
148
|
+
get close() {
|
|
149
|
+
return close;
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
createOpenClosedContext({
|
|
153
|
+
get value() {
|
|
154
|
+
return context.popoverState === PopoverStates.Open ? State.Open : State.Closed;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
</script>
|
|
158
|
+
|
|
159
|
+
<MainTreeProvider node={mainTreeNode.node}>
|
|
160
|
+
<ElementOrComponent {theirProps} slots={slot} defaultTag={DEFAULT_POPOVER_TAG} name="Popover" bind:ref />
|
|
161
|
+
</MainTreeProvider>
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { ElementType, Props } from "../utils/types.js";
|
|
2
|
+
export declare const DEFAULT_POPOVER_TAG: "div";
|
|
3
|
+
type PopoverRenderPropArg = {
|
|
4
|
+
open: boolean;
|
|
5
|
+
close(focusableElement?: HTMLElement | MouseEvent<HTMLElement>): void;
|
|
6
|
+
};
|
|
7
|
+
type PopoverPropsWeControl = never;
|
|
8
|
+
export type PopoverProps<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG> = Props<TTag, PopoverRenderPropArg, PopoverPropsWeControl, {
|
|
9
|
+
__demoMode?: boolean;
|
|
10
|
+
}>;
|
|
11
|
+
import { type MouseEvent } from "./context.svelte.js";
|
|
12
|
+
declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG> {
|
|
13
|
+
props(): {
|
|
14
|
+
as?: TTag | undefined;
|
|
15
|
+
} & (Exclude<keyof import("../utils/types.js").PropsOf<TTag>, ("as" | "children" | "refName" | "class") | "__demoMode"> extends infer T extends keyof import("../utils/types.js").PropsOf<TTag> ? { [P in T]: import("../utils/types.js").PropsOf<TTag>[P]; } : never) & {
|
|
16
|
+
children?: import("svelte").Snippet<[PopoverRenderPropArg, Record<string, any>]> | undefined;
|
|
17
|
+
ref?: HTMLElement;
|
|
18
|
+
} & (true extends (import("../utils/types.js").PropsOf<TTag> extends infer T_1 ? T_1 extends import("../utils/types.js").PropsOf<TTag> ? T_1 extends never ? never : "class" extends infer T_2 ? T_2 extends "class" ? T_2 extends keyof T_1 ? true : never : never : never : never : never) ? {
|
|
19
|
+
class?: import("../utils/types.js").PropsOf<TTag>["class"] | ((bag: PopoverRenderPropArg) => string) | undefined;
|
|
20
|
+
} : {}) & {
|
|
21
|
+
__demoMode?: boolean;
|
|
22
|
+
};
|
|
23
|
+
events(): {} & {
|
|
24
|
+
[evt: string]: CustomEvent<any>;
|
|
25
|
+
};
|
|
26
|
+
slots(): {};
|
|
27
|
+
bindings(): "ref";
|
|
28
|
+
exports(): {};
|
|
29
|
+
}
|
|
30
|
+
interface $$IsomorphicComponent {
|
|
31
|
+
new <TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TTag>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TTag>['props']>, ReturnType<__sveltets_Render<TTag>['events']>, ReturnType<__sveltets_Render<TTag>['slots']>> & {
|
|
32
|
+
$$bindings?: ReturnType<__sveltets_Render<TTag>['bindings']>;
|
|
33
|
+
} & ReturnType<__sveltets_Render<TTag>['exports']>;
|
|
34
|
+
<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG>(internal: unknown, props: ReturnType<__sveltets_Render<TTag>['props']> & {
|
|
35
|
+
$$events?: ReturnType<__sveltets_Render<TTag>['events']>;
|
|
36
|
+
}): ReturnType<__sveltets_Render<TTag>['exports']>;
|
|
37
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
38
|
+
}
|
|
39
|
+
declare const Popover: $$IsomorphicComponent;
|
|
40
|
+
type Popover<TTag extends ElementType = typeof DEFAULT_POPOVER_TAG> = InstanceType<typeof Popover<TTag>>;
|
|
41
|
+
export default Popover;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
<script lang="ts" module>import { RenderFeatures } from "../utils/render.js";
|
|
2
|
+
let DEFAULT_BACKDROP_TAG = "div";
|
|
3
|
+
const BackdropRenderFeatures = RenderFeatures.RenderStrategy | RenderFeatures.Static;
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script lang="ts" generics="TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG">import ElementOrComponent from "../utils/ElementOrComponent.svelte";
|
|
7
|
+
import { useId } from "../hooks/use-id.js";
|
|
8
|
+
import { PopoverStates, usePopoverContext } from "./context.svelte.js";
|
|
9
|
+
import { State, useOpenClosed } from "../internal/open-closed.js";
|
|
10
|
+
import { transitionDataAttributes, useTransition } from "../hooks/use-transition.svelte.js";
|
|
11
|
+
const internalId = useId();
|
|
12
|
+
let {
|
|
13
|
+
ref = $bindable(),
|
|
14
|
+
id = `headlessui-popover-backdrop-${internalId}`,
|
|
15
|
+
transition = false,
|
|
16
|
+
...theirProps
|
|
17
|
+
} = $props();
|
|
18
|
+
const context = usePopoverContext("PopoverBackdrop");
|
|
19
|
+
const { popoverState } = $derived(context);
|
|
20
|
+
const usesOpenClosedState = useOpenClosed();
|
|
21
|
+
const _transition = useTransition({
|
|
22
|
+
get enabled() {
|
|
23
|
+
return transition;
|
|
24
|
+
},
|
|
25
|
+
get element() {
|
|
26
|
+
return ref;
|
|
27
|
+
},
|
|
28
|
+
get show() {
|
|
29
|
+
return usesOpenClosedState !== null ? (usesOpenClosedState.value & State.Open) === State.Open : popoverState === PopoverStates.Open;
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
const { visible, data: transitionData } = $derived(_transition);
|
|
33
|
+
const handleClick = (event) => {
|
|
34
|
+
context.closePopover();
|
|
35
|
+
};
|
|
36
|
+
const slot = $derived({
|
|
37
|
+
open: popoverState === PopoverStates.Open
|
|
38
|
+
});
|
|
39
|
+
const ourProps = $derived({
|
|
40
|
+
id,
|
|
41
|
+
"aria-hidden": true,
|
|
42
|
+
onclick: handleClick,
|
|
43
|
+
...transitionDataAttributes(transitionData)
|
|
44
|
+
});
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<ElementOrComponent
|
|
48
|
+
{ourProps}
|
|
49
|
+
{theirProps}
|
|
50
|
+
slots={slot}
|
|
51
|
+
defaultTag={DEFAULT_BACKDROP_TAG}
|
|
52
|
+
features={BackdropRenderFeatures}
|
|
53
|
+
name="PopoverBackdrop"
|
|
54
|
+
{visible}
|
|
55
|
+
bind:ref
|
|
56
|
+
/>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ElementType, Props, PropsOf } from "../utils/types.js";
|
|
2
|
+
import { type PropsForFeatures } from "../utils/render.js";
|
|
3
|
+
declare let DEFAULT_BACKDROP_TAG: "div";
|
|
4
|
+
type BackdropRenderPropArg = {
|
|
5
|
+
open: boolean;
|
|
6
|
+
};
|
|
7
|
+
type BackdropPropsWeControl = "aria-hidden";
|
|
8
|
+
declare const BackdropRenderFeatures: number;
|
|
9
|
+
export type PopoverBackdropProps<TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG> = Props<TTag, BackdropRenderPropArg, BackdropPropsWeControl, {
|
|
10
|
+
transition?: boolean;
|
|
11
|
+
} & PropsForFeatures<typeof BackdropRenderFeatures>>;
|
|
12
|
+
export type PopoverOverlayProps<TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG> = PopoverBackdropProps<TTag>;
|
|
13
|
+
declare class __sveltets_Render<TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG> {
|
|
14
|
+
props(): {
|
|
15
|
+
as?: TTag | undefined;
|
|
16
|
+
} & (Exclude<keyof PropsOf<TTag>, ("as" | "children" | "refName" | "class") | "unmount" | "static" | "aria-hidden" | "transition"> extends infer T extends keyof PropsOf<TTag> ? { [P in T]: PropsOf<TTag>[P]; } : never) & {
|
|
17
|
+
children?: import("svelte").Snippet<[BackdropRenderPropArg, Record<string, any>]> | undefined;
|
|
18
|
+
ref?: HTMLElement;
|
|
19
|
+
} & (true extends (PropsOf<TTag> extends infer T_1 ? T_1 extends PropsOf<TTag> ? T_1 extends never ? never : "class" extends infer T_2 ? T_2 extends "class" ? T_2 extends keyof T_1 ? true : never : never : never : never : never) ? {
|
|
20
|
+
class?: PropsOf<TTag>["class"] | ((bag: BackdropRenderPropArg) => string) | undefined;
|
|
21
|
+
} : {}) & {
|
|
22
|
+
transition?: boolean;
|
|
23
|
+
} & {
|
|
24
|
+
static?: boolean | undefined;
|
|
25
|
+
unmount?: boolean | undefined;
|
|
26
|
+
};
|
|
27
|
+
events(): {} & {
|
|
28
|
+
[evt: string]: CustomEvent<any>;
|
|
29
|
+
};
|
|
30
|
+
slots(): {};
|
|
31
|
+
bindings(): "ref";
|
|
32
|
+
exports(): {};
|
|
33
|
+
}
|
|
34
|
+
interface $$IsomorphicComponent {
|
|
35
|
+
new <TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG>(options: import('svelte').ComponentConstructorOptions<ReturnType<__sveltets_Render<TTag>['props']>>): import('svelte').SvelteComponent<ReturnType<__sveltets_Render<TTag>['props']>, ReturnType<__sveltets_Render<TTag>['events']>, ReturnType<__sveltets_Render<TTag>['slots']>> & {
|
|
36
|
+
$$bindings?: ReturnType<__sveltets_Render<TTag>['bindings']>;
|
|
37
|
+
} & ReturnType<__sveltets_Render<TTag>['exports']>;
|
|
38
|
+
<TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG>(internal: unknown, props: ReturnType<__sveltets_Render<TTag>['props']> & {
|
|
39
|
+
$$events?: ReturnType<__sveltets_Render<TTag>['events']>;
|
|
40
|
+
}): ReturnType<__sveltets_Render<TTag>['exports']>;
|
|
41
|
+
z_$$bindings?: ReturnType<__sveltets_Render<any>['bindings']>;
|
|
42
|
+
}
|
|
43
|
+
declare const PopoverBackdrop: $$IsomorphicComponent;
|
|
44
|
+
type PopoverBackdrop<TTag extends ElementType = typeof DEFAULT_BACKDROP_TAG> = InstanceType<typeof PopoverBackdrop<TTag>>;
|
|
45
|
+
export default PopoverBackdrop;
|