Skip to content

Commit 7cce28a

Browse files
committed
some stuff
1 parent 6f2f035 commit 7cce28a

File tree

20 files changed

+474
-49
lines changed

20 files changed

+474
-49
lines changed

packages/floating-ui-svelte/src/components/floating-focus-manager/floating-focus-manager.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,9 @@
201201
let tabbableIndex = $state(-1);
202202
203203
const isInsidePortal = portalContext != null;
204+
205+
console.log("isInsidePortal", isInsidePortal);
206+
204207
const floatingFocusElement = $derived(
205208
getFloatingFocusElement(context.floating)
206209
);
@@ -422,8 +425,8 @@
422425
context.floating,
423426
...portalNodes,
424427
...ancestorFloatingNodes,
425-
startDismissButtonRef,
426-
endDismissButtonRef,
428+
startDismissButtonRef.current,
429+
endDismissButtonRef.current,
427430
beforeGuardRef.current,
428431
afterGuardRef.current,
429432
portalContext?.beforeOutsideRef.current,

packages/floating-ui-svelte/src/components/floating-portal/floating-portal.svelte

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,12 @@
4141

4242
<script lang="ts">
4343
import Portal from "./portal.svelte";
44-
import type { Boxed } from "../../types.js";
44+
import { box } from "../../internal/box.svelte.js";
4545
4646
let {
4747
children,
4848
id,
49-
root = null,
49+
root = typeof document === "undefined" ? null : document.body,
5050
preserveTabOrder = true,
5151
}: FloatingPortalProps = $props();
5252
@@ -56,18 +56,10 @@
5656
});
5757
5858
let focusManagerState = $state.raw<FocusManagerState>(null);
59-
let beforeOutsideRef = $state<Boxed<HTMLSpanElement | null>>({
60-
current: null,
61-
});
62-
let afterOutsideRef = $state<Boxed<HTMLSpanElement | null>>({
63-
current: null,
64-
});
65-
let beforeInsideRef = $state<Boxed<HTMLSpanElement | null>>({
66-
current: null,
67-
});
68-
let afterInsideRef = $state<Boxed<HTMLSpanElement | null>>({
69-
current: null,
70-
});
59+
const beforeOutsideRef = box<HTMLSpanElement | null>(null);
60+
const afterOutsideRef = box<HTMLSpanElement | null>(null);
61+
const beforeInsideRef = box<HTMLSpanElement | null>(null);
62+
const afterInsideRef = box<HTMLSpanElement | null>(null);
7163
7264
const modal = $derived(focusManagerState?.modal);
7365
const open = $derived(focusManagerState?.open);
@@ -92,13 +84,13 @@
9284
// portal has already been focused, either by tabbing into a focus trap
9385
// element outside or using the mouse.
9486
function onFocus(event: FocusEvent) {
95-
if (!portalNode || !isOutsideEvent(event)) return;
96-
97-
const focusing = event.type === "focusin";
98-
const manageFocus = focusing
99-
? enableFocusInside
100-
: disableFocusInside;
101-
manageFocus(portalNode);
87+
if (portalNode && isOutsideEvent(event)) {
88+
const focusing = event.type === "focusin";
89+
const manageFocus = focusing
90+
? enableFocusInside
91+
: disableFocusInside;
92+
manageFocus(portalNode);
93+
}
10294
}
10395
10496
return executeCallbacks(
@@ -134,7 +126,7 @@
134126
{#if shouldRenderGuards && portalNode.current}
135127
<FocusGuard
136128
data-type="outside"
137-
ref={beforeOutsideRef.current}
129+
bind:ref={beforeOutsideRef.current}
138130
onfocus={(event) => {
139131
if (isOutsideEvent(event, portalNode.current)) {
140132
beforeInsideRef.current?.focus();
@@ -155,7 +147,7 @@
155147
{#if shouldRenderGuards && portalNode.current}
156148
<FocusGuard
157149
data-type="outside"
158-
ref={afterOutsideRef.current}
150+
bind:ref={afterOutsideRef.current}
159151
onfocus={(event) => {
160152
if (isOutsideEvent(event, portalNode.current)) {
161153
afterInsideRef.current?.focus();

packages/floating-ui-svelte/src/components/floating-portal/hooks.svelte.ts

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,17 +43,14 @@ function useFloatingPortalNode(props: UseFloatingPortalNodeProps = {}) {
4343

4444
let portalNode = $state<HTMLElement | null>(null);
4545

46-
watch(
47-
() => portalNode,
48-
() => {
49-
return () => {
50-
portalNode?.remove();
51-
queueMicrotask(() => {
52-
portalNode = null;
53-
});
54-
};
55-
},
56-
);
46+
$effect(() => {
47+
return () => {
48+
portalNode?.remove();
49+
queueMicrotask(() => {
50+
portalNode = null;
51+
});
52+
};
53+
});
5754

5855
watch(
5956
() => id,

packages/floating-ui-svelte/src/components/floating-tree/floating-node.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,11 @@
55
useFloatingParentNodeId,
66
} from "./hooks.svelte.js";
77
8-
export interface FloatingNodeProps {
8+
interface FloatingNodeProps {
99
children?: Snippet;
1010
id: string | undefined;
1111
}
12+
export type { FloatingNodeProps };
1213
</script>
1314

1415
<script lang="ts">

packages/floating-ui-svelte/src/components/floating-tree/floating-tree.svelte

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,10 @@
44
import { createPubSub } from "../../internal/create-pub-sub.js";
55
import { FloatingTreeContext } from "./hooks.svelte.js";
66
7-
export interface FloatingTreeProps {
7+
interface FloatingTreeProps {
88
children?: Snippet;
99
}
10+
export type { FloatingTreeProps };
1011
</script>
1112

1213
<script lang="ts">
Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { untrack } from "svelte";
12
import { useId } from "../../hooks/use-id.js";
23
import { Context } from "../../internal/context.js";
34
import type {
@@ -6,26 +7,26 @@ import type {
67
ReferenceType,
78
} from "../../types.js";
89

9-
export const FloatingNodeContext = new Context<FloatingNodeType>(
10+
const FloatingNodeContext = new Context<FloatingNodeType>(
1011
"FloatingNodeContext",
1112
);
1213

13-
export const FloatingTreeContext = new Context<FloatingTreeType>(
14+
const FloatingTreeContext = new Context<FloatingTreeType>(
1415
"FloatingTreeContext",
1516
);
1617

1718
/**
1819
* Returns the parent node id for nested floating elements, if available.
1920
* Returns `null` for top-level floating elements.
2021
*/
21-
export function useFloatingParentNodeId(): string | null {
22+
function useFloatingParentNodeId(): string | null {
2223
return FloatingNodeContext.getOr(null)?.id || null;
2324
}
2425

2526
/**
2627
* Returns the nearest floating tree context, if available.
2728
*/
28-
export function useFloatingTree<
29+
function useFloatingTree<
2930
RT extends ReferenceType = ReferenceType,
3031
>(): FloatingTreeType<RT> | null {
3132
return FloatingTreeContext.getOr(null) as FloatingTreeType<RT> | null;
@@ -35,19 +36,29 @@ export function useFloatingTree<
3536
* Registers a node into the `FloatingTree`, returning its id.
3637
* @see https://floating-ui-svelte.vercel.app/docs/api/use-floating-node-id
3738
*/
38-
export function useFloatingNodeId(customParentId?: string): string | undefined {
39+
function useFloatingNodeId(customParentId?: string): string | undefined {
3940
const id = useId();
4041
const tree = useFloatingTree();
4142
const _parentId = useFloatingParentNodeId();
4243
const parentId = customParentId || _parentId;
4344

4445
$effect(() => {
4546
const node = { id, parentId };
46-
tree?.addNode(node);
47+
untrack(() => {
48+
tree?.addNode(node);
49+
});
4750
return () => {
4851
tree?.removeNode(node);
4952
};
5053
});
5154

5255
return id;
5356
}
57+
58+
export {
59+
useFloatingNodeId,
60+
useFloatingParentNodeId,
61+
useFloatingTree,
62+
FloatingNodeContext,
63+
FloatingTreeContext,
64+
};

packages/floating-ui-svelte/src/hooks/use-floating.svelte.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ interface UseFloatingOptions<RT extends ReferenceType = ReferenceType> {
9191
/**
9292
* Unique node id when using `FloatingTree`.
9393
*/
94-
nodeId?: MaybeGetter<string>;
94+
nodeId?: MaybeGetter<string | undefined>;
9595
}
9696

9797
/**

packages/floating-ui-svelte/src/index.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,19 @@
44
export * from "./components/floating-arrow.svelte";
55
export { default as FloatingArrow } from "./components/floating-arrow.svelte";
66

7+
export * from "./components/floating-portal/floating-portal.svelte";
8+
export { default as FloatingPortal } from "./components/floating-portal/floating-portal.svelte";
9+
export * from "./components/floating-portal/hooks.svelte.js";
10+
11+
export * from "./components/floating-tree/floating-tree.svelte";
12+
export { default as FloatingTree } from "./components/floating-tree/floating-tree.svelte";
13+
export * from "./components/floating-tree/floating-node.svelte";
14+
export { default as FloatingNode } from "./components/floating-tree/floating-node.svelte";
15+
export * from "./components/floating-tree/hooks.svelte.js";
16+
17+
export * from "./components/floating-focus-manager/floating-focus-manager.svelte";
18+
export { default as FloatingFocusManager } from "./components/floating-focus-manager/floating-focus-manager.svelte";
19+
720
/**
821
* Hooks
922
*/

packages/floating-ui-svelte/test/components/floating-arrow.ts renamed to packages/floating-ui-svelte/test/components/floating-arrow.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { render, screen } from "@testing-library/svelte";
22
import { describe, expect, it } from "vitest";
33
import FloatingArrow from "../../src/components/floating-arrow.svelte";
4-
import { useFloating } from "../../src/hooks/use-position.svelte.js";
54
import { withRunes } from "../internal/with-runes.svelte.js";
5+
import { useFloating } from "../../src/index.js";
66

77
describe("FloatingArrow", () => {
88
it(
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<script lang="ts">
2+
import type { Snippet } from "svelte";
3+
import FloatingNode from "../../../src/components/floating-tree/floating-node.svelte";
4+
import {
5+
useClick,
6+
useDismiss,
7+
useFloating,
8+
useFloatingNodeId,
9+
useInteractions,
10+
type Boxed,
11+
} from "../../../src/index.js";
12+
import { box } from "../../../src/internal/box.svelte.js";
13+
import FloatingPortal from "../../../src/components/floating-portal/floating-portal.svelte";
14+
import FloatingFocusManager from "../../../src/components/floating-focus-manager/floating-focus-manager.svelte";
15+
16+
let {
17+
open: passedOpen = false,
18+
reference,
19+
content,
20+
}: {
21+
open?: boolean;
22+
reference: Snippet<
23+
[ref: Boxed<Element | null>, props: Record<string, unknown>]
24+
>;
25+
content: Snippet<[close: () => void]>;
26+
} = $props();
27+
28+
let open = $state(passedOpen);
29+
const nodeId = useFloatingNodeId();
30+
31+
const referenceRef = box<Element | null>(null);
32+
33+
const floating = useFloating({
34+
open: () => open,
35+
onOpenChange: (v) => {
36+
open = v;
37+
},
38+
nodeId: () => nodeId,
39+
reference: () => referenceRef.current,
40+
onReferenceChange: (v) => {
41+
referenceRef.current = v;
42+
},
43+
});
44+
45+
const ints = useInteractions([
46+
useClick(floating.context),
47+
useDismiss(floating.context, { bubbles: false }),
48+
]);
49+
</script>
50+
51+
<FloatingNode id={nodeId}>
52+
{@render reference(referenceRef, ints.getReferenceProps())}
53+
<FloatingPortal>
54+
{#if open}
55+
<FloatingFocusManager context={floating.context}>
56+
<div {...ints.getFloatingProps()} bind:this={floating.floating}>
57+
{@render content(close)}
58+
</div>
59+
</FloatingFocusManager>
60+
{/if}
61+
</FloatingPortal>
62+
</FloatingNode>

0 commit comments

Comments
 (0)