Skip to content

Commit 35203e9

Browse files
committed
whew
1 parent 6ff3339 commit 35203e9

File tree

10 files changed

+453
-479
lines changed

10 files changed

+453
-479
lines changed

packages/floating-ui-svelte/src/components/floating-arrow.svelte renamed to packages/floating-ui-svelte/src/components/floating-tree/floating-arrow.svelte

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script lang="ts" module>
22
import type { SVGAttributes } from "svelte/elements";
3-
import type { FloatingContext } from "../../src/index.js";
3+
import type { FloatingContext } from "../../hooks/use-floating.svelte.js";
44
55
export interface FloatingArrowProps extends SVGAttributes<SVGElement> {
66
/** The bound HTML element reference. */
@@ -54,8 +54,8 @@
5454
<script lang="ts">
5555
import type { Alignment, Side } from "@floating-ui/dom";
5656
import { platform } from "@floating-ui/dom";
57-
import { useId } from "../hooks/use-id.js";
58-
import { styleObjectToString } from "../internal/style-object-to-string.js";
57+
import { useId } from "../../hooks/use-id.js";
58+
import { styleObjectToString } from "../../internal/style-object-to-string.js";
5959
6060
let {
6161
ref = $bindable(null),
@@ -75,12 +75,6 @@
7575
...rest
7676
}: FloatingArrowProps = $props();
7777
78-
const {
79-
placement,
80-
elements: { floating },
81-
middlewareData: { arrow },
82-
} = $derived(context);
83-
8478
const clipPathId = useId();
8579
8680
// Strokes must be double the border width, this ensures the stroke's width
@@ -92,9 +86,11 @@
9286
const svgY = $derived(((height / 2) * tipRadius) / 4);
9387
9488
const [side, alignment] = $derived(
95-
placement.split("-") as [Side, Alignment]
89+
context.placement.split("-") as [Side, Alignment]
90+
);
91+
const isRTL = $derived(
92+
context.elements.floating && platform.isRTL(context.elements.floating)
9693
);
97-
const isRTL = $derived(floating && platform.isRTL(floating));
9894
const isCustomShape = $derived(!!d);
9995
const isVerticalSide = $derived(side === "top" || side === "bottom");
10096

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
<script lang="ts" module>
22
import type { Snippet } from "svelte";
3-
import type { FloatingNodeType } from "../../types.js";
3+
import type {
4+
FloatingNodeType,
5+
FloatingTreeType,
6+
ReferenceType,
7+
} from "../../types.js";
48
import { createPubSub } from "../../internal/create-pub-sub.js";
59
import { FloatingTreeContext } from "./hooks.svelte.js";
610

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

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { useId } from "../../hooks/use-id.js";
22
import { Context } from "../../internal/context.js";
3-
import type { FloatingNodeType, FloatingTreeType } from "../../types.js";
3+
import type {
4+
FloatingNodeType,
5+
FloatingTreeType,
6+
ReferenceType,
7+
} from "../../types.js";
48

59
export const FloatingNodeContext = new Context<FloatingNodeType>(
610
"FloatingNodeContext",
@@ -21,8 +25,10 @@ export function useFloatingParentNodeId(): string | null {
2125
/**
2226
* Returns the nearest floating tree context, if available.
2327
*/
24-
export function useFloatingTree(): FloatingTreeType | null {
25-
return FloatingTreeContext.getOr(null);
28+
export function useFloatingTree<
29+
RT extends ReferenceType = ReferenceType,
30+
>(): FloatingTreeType<RT> | null {
31+
return FloatingTreeContext.getOr(null) as FloatingTreeType<RT> | null;
2632
}
2733

2834
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { isHTMLElement } from "@floating-ui/utils/dom";
22
import { isMouseLikePointerType } from "../internal/dom.js";
33
import { isTypeableElement } from "../internal/is-typeable-element.js";
44
import type { ElementProps } from "./use-interactions.svelte.js";
5-
import type { FloatingContext } from "../types.js";
5+
import type { FloatingContext } from "./use-floating.svelte.js";
66

77
interface UseClickOptions {
88
/**

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
isEventTargetWithin,
1414
isRootElement,
1515
} from "../internal/dom.js";
16-
import type { FloatingContext } from "../types.js";
16+
import type { FloatingContext } from "./use-floating.svelte.js";
1717

1818
const bubbleHandlerKeys = {
1919
pointerdown: "onpointerdown",
Lines changed: 70 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { ReferenceElement } from "@floating-ui/dom";
22
import type {
33
ContextData,
4-
FloatingEvents,
4+
OnOpenChange,
55
OpenChangeReason,
66
ReferenceType,
77
} from "../types.js";
@@ -11,7 +11,6 @@ import { useFloatingParentNodeId } from "../components/floating-tree/hooks.svelt
1111
import { DEV } from "esm-env";
1212
import { isElement } from "@floating-ui/utils/dom";
1313
import { error } from "../internal/log.js";
14-
import { noop } from "../internal/noop.js";
1514

1615
interface UseFloatingRootContextOptions {
1716
open?: boolean;
@@ -26,123 +25,93 @@ interface UseFloatingRootContextOptions {
2625
};
2726
}
2827

29-
interface FloatingRootContext<RT extends ReferenceType = ReferenceType> {
30-
data: ContextData;
31-
open: boolean;
32-
onOpenChange: (
33-
open: boolean,
34-
event?: Event,
35-
reason?: OpenChangeReason,
36-
) => void;
37-
elements: {
38-
domReference: Element | null;
39-
reference: RT | null;
40-
floating: HTMLElement | null;
41-
};
42-
events: FloatingEvents;
43-
floatingId: string | undefined;
44-
refs: {
45-
setPositionReference(node: ReferenceType | null): void;
46-
};
47-
}
28+
class FloatingRootContext<RT extends ReferenceType = ReferenceType> {
29+
floatingId = useId();
30+
data: ContextData<RT> = $state({});
31+
events = createPubSub();
32+
open = $derived.by(() => this.options.open ?? false);
4833

49-
/**
50-
* Creates a floating root context to manage the state of a floating element.
51-
*/
52-
function useFloatingRootContext(
53-
options: UseFloatingRootContextOptions,
54-
): FloatingRootContext {
55-
const elementsProp: {
56-
reference: ReferenceType | null;
57-
floating: HTMLElement | null;
58-
} = $state(options.elements);
34+
/** Whether the floating element is nested inside another floating element. */
35+
#nested: boolean;
36+
/** Enables the user to specify a position reference after initialization. */
37+
#positionReference = $state<ReferenceElement | null>(null);
38+
#referenceElement = $state<Element | null>(null);
39+
#floatingElement = $state<HTMLElement | null>(null);
5940

60-
$effect.pre(() => {
61-
if (!options.elements || !options.elements.reference) {
62-
return;
63-
}
64-
elementsProp.reference = options.elements.reference;
65-
});
41+
#elements = $derived.by(() => ({
42+
reference: (this.#positionReference ||
43+
this.#referenceElement ||
44+
null) as RT | null,
45+
floating: this.#floatingElement || null,
46+
domReference: this.#referenceElement as Element | null,
47+
}));
6648

67-
$effect.pre(() => {
68-
if (!options.elements || !options.elements.floating) {
69-
return;
70-
}
71-
elementsProp.floating = options.elements.floating;
72-
});
49+
constructor(private readonly options: UseFloatingRootContextOptions) {
50+
this.#nested = useFloatingParentNodeId() != null;
7351

74-
const { open = false, onOpenChange: onOpenChangeProp = noop } = options;
52+
this.#referenceElement = this.options.elements.reference;
53+
this.#floatingElement = this.options.elements.floating;
7554

76-
const floatingId = useId();
77-
const data = $state<ContextData>({});
78-
const events = createPubSub();
79-
const nested = useFloatingParentNodeId() != null;
55+
$effect.pre(() => {
56+
this.#referenceElement = this.options.elements.reference;
57+
});
8058

81-
if (DEV) {
82-
const optionDomReference = elementsProp.reference;
83-
if (optionDomReference && !isElement(optionDomReference)) {
84-
error(
85-
"Cannot pass a virtual element to the `elements.reference` option,",
86-
"as it must be a real DOM element. Use `refs.setPositionReference()`",
87-
"instead.",
88-
);
59+
$effect.pre(() => {
60+
this.#floatingElement = this.options.elements.floating;
61+
});
62+
63+
if (DEV) {
64+
if (
65+
options.elements.reference &&
66+
!isElement(options.elements.reference)
67+
) {
68+
error(
69+
"Cannot pass a virtual element to the `elements.reference` option,",
70+
"as it must be a real DOM element. Use `floating.setPositionReference()`",
71+
"instead.",
72+
);
73+
}
8974
}
75+
this.#positionReference = options.elements.reference;
9076
}
9177

92-
// Enable the user to set the position reference later to something other than
93-
// what it was initialized with
94-
let positionReference = $state<ReferenceElement | null>(
95-
elementsProp.reference,
96-
);
97-
98-
const onOpenChange = (
99-
open: boolean,
100-
event?: Event,
101-
reason?: OpenChangeReason,
102-
) => {
103-
data.openEvent = open ? event : undefined;
104-
events.emit("openchange", { open, event, reason, nested });
105-
onOpenChangeProp(open, event, reason);
78+
onOpenChange: OnOpenChange = (open, event, reason) => {
79+
this.data.openEvent = open ? event : undefined;
80+
this.events.emit("openchange", {
81+
open,
82+
event,
83+
reason,
84+
nested: this.#nested,
85+
});
86+
this.options.onOpenChange?.(open, event, reason);
10687
};
10788

108-
const elements = $derived({
109-
reference: positionReference || elementsProp.reference || null,
110-
floating: elementsProp.floating || null,
111-
domReference: elementsProp.reference as Element | null,
112-
});
89+
setPositionReference = (node: ReferenceElement | null) => {
90+
this.#positionReference = node;
91+
};
11392

114-
return {
115-
data,
116-
get open() {
117-
return open;
118-
},
119-
onOpenChange,
120-
elements: {
93+
get elements() {
94+
const _this = this;
95+
return {
12196
get reference() {
122-
return elements.reference;
123-
},
124-
set reference(v: ReferenceType | null) {
125-
elementsProp.reference = v;
97+
return _this.#elements.reference;
12698
},
12799
get floating() {
128-
return elements.floating;
100+
return _this.#elements.floating;
129101
},
130-
set floating(v: HTMLElement | null) {
131-
elementsProp.floating = v;
102+
set floating(node: HTMLElement | null) {
103+
_this.#floatingElement = node;
132104
},
133105
get domReference() {
134-
return elements.domReference;
135-
},
136-
},
137-
events,
138-
floatingId,
139-
refs: {
140-
setPositionReference(node: ReferenceElement | null) {
141-
positionReference = node;
106+
return _this.#referenceElement;
142107
},
143-
},
144-
};
108+
};
109+
}
110+
}
111+
112+
export function useFloatingRootContext(options: UseFloatingRootContextOptions) {
113+
return new FloatingRootContext(options);
145114
}
146115

147-
export { useFloatingRootContext };
148-
export type { FloatingRootContext, UseFloatingRootContextOptions };
116+
export type { UseFloatingRootContextOptions };
117+
export { FloatingRootContext };

0 commit comments

Comments
 (0)