Skip to content

Commit 8988a65

Browse files
committed
closer but not yet
1 parent 09cf58f commit 8988a65

16 files changed

+271
-172
lines changed

packages/floating-ui-svelte/package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
"test:watch": "pnpm test --watch",
1010
"sync": "svelte-kit sync && pnpm build"
1111
},
12-
"files": ["dist"],
12+
"files": [
13+
"dist"
14+
],
1315
"sideEffects": false,
1416
"svelte": "./dist/index.js",
1517
"types": "./dist/index.d.ts",
@@ -36,7 +38,7 @@
3638
"@testing-library/svelte": "^5.2.6",
3739
"@testing-library/user-event": "^14.5.2",
3840
"csstype": "^3.1.3",
39-
"svelte": "^5.16.0",
41+
"svelte": "^5.17.3",
4042
"typescript": "^5.7.2",
4143
"vite": "^6.0.6",
4244
"vitest": "^2.1.8"

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

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,28 +2,29 @@ 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 { FloatingContext } from "./use-floating.svelte.js";
5-
import type { ReferenceType } from "../types.js";
5+
import type { MaybeGetter, ReferenceType } from "../types.js";
6+
import { extract } from "../internal/extract.js";
67

78
interface UseClickOptions {
89
/**
910
* Whether the Hook is enabled, including all internal Effects and event
1011
* handlers.
1112
* @default true
1213
*/
13-
enabled?: boolean;
14+
enabled?: MaybeGetter<boolean>;
1415

1516
/**
1617
* The type of event to use to determine a “click” with mouse input.
1718
* Keyboard clicks work as normal.
1819
* @default 'click'
1920
*/
20-
event?: "click" | "mousedown";
21+
event?: MaybeGetter<"click" | "mousedown">;
2122

2223
/**
2324
* Whether to toggle the open state with repeated clicks.
2425
* @default true
2526
*/
26-
toggle?: boolean;
27+
toggle?: MaybeGetter<boolean>;
2728

2829
/**
2930
* Whether to ignore the logic for mouse input (for example, if `useHover()`
@@ -33,15 +34,15 @@ interface UseClickOptions {
3334
* even once the cursor leaves. This may be not be desirable in some cases.
3435
* @default false
3536
*/
36-
ignoreMouse?: boolean;
37+
ignoreMouse?: MaybeGetter<boolean>;
3738

3839
/**
3940
* Whether to add keyboard handlers (Enter and Space key functionality) for
4041
* non-button elements (to open/close the floating element via keyboard
4142
* “click”).
4243
* @default true
4344
*/
44-
keyboardHandlers?: boolean;
45+
keyboardHandlers?: MaybeGetter<boolean>;
4546
}
4647

4748
function isButtonTarget(event: KeyboardEvent) {
@@ -53,11 +54,13 @@ function isSpaceIgnored(element: ReferenceType | null) {
5354
}
5455

5556
class ClickInteraction {
56-
#enabled = $derived.by(() => this.options.enabled ?? "true");
57-
#eventOption = $derived.by(() => this.options.event ?? "click");
58-
#toggle = $derived.by(() => this.options.toggle ?? true);
59-
#ignoreMouse = $derived.by(() => this.options.ignoreMouse ?? false);
60-
#keyboardHandlers = $derived.by(() => this.options.keyboardHandlers ?? true);
57+
#enabled = $derived.by(() => extract(this.options?.enabled, true));
58+
#eventOption = $derived.by(() => extract(this.options?.event, "click"));
59+
#toggle = $derived.by(() => extract(this.options?.toggle, true));
60+
#ignoreMouse = $derived.by(() => extract(this.options?.ignoreMouse, false));
61+
#keyboardHandlers = $derived.by(() =>
62+
extract(this.options?.keyboardHandlers, true),
63+
);
6164
#pointerType: PointerEvent["pointerType"] | undefined = undefined;
6265
#didKeyDown = false;
6366

@@ -127,10 +130,7 @@ class ClickInteraction {
127130
return;
128131
}
129132

130-
if (
131-
event.key === " " &&
132-
!isSpaceIgnored(this.context.elements.domReference)
133-
) {
133+
if (event.key === " " && !isSpaceIgnored(this.context.domReference)) {
134134
// Prevent scrolling
135135
event.preventDefault();
136136
this.#didKeyDown = true;
@@ -150,7 +150,7 @@ class ClickInteraction {
150150
event.defaultPrevented ||
151151
!this.#keyboardHandlers ||
152152
isButtonTarget(event) ||
153-
isSpaceIgnored(this.context.elements.domReference)
153+
isSpaceIgnored(this.context.domReference)
154154
) {
155155
return;
156156
}

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

Lines changed: 44 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,12 @@ import {
1515
isRootElement,
1616
} from "../internal/dom.js";
1717
import type { FloatingContext } from "./use-floating.svelte.js";
18-
import type { FloatingTreeType } from "../types.js";
18+
import type { FloatingTreeType, MaybeGetter } from "../types.js";
1919
import { useFloatingTree } from "../components/floating-tree/hooks.svelte.js";
2020
import { getChildren } from "../internal/get-children.js";
2121
import { on } from "svelte/events";
2222
import { executeCallbacks } from "../internal/execute-callbacks.js";
23+
import { extract } from "../internal/extract.js";
2324

2425
const bubbleHandlerKeys = {
2526
pointerdown: "onpointerdown",
@@ -54,27 +55,27 @@ interface UseDismissOptions {
5455
* handlers.
5556
* @default true
5657
*/
57-
enabled?: boolean;
58+
enabled?: MaybeGetter<boolean>;
5859
/**
5960
* Whether to dismiss the floating element upon pressing the `esc` key.
6061
* @default true
6162
*/
62-
escapeKey?: boolean;
63+
escapeKey?: MaybeGetter<boolean>;
6364
/**
6465
* Whether to dismiss the floating element upon pressing the reference
6566
* element. You likely want to ensure the `move` option in the `useHover()`
6667
* Hook has been disabled when this is in use.
6768
* @default false
6869
*/
69-
referencePress?: boolean;
70+
referencePress?: MaybeGetter<boolean>;
7071
/**
7172
* The type of event to use to determine a “press”.
7273
* - `pointerdown` is eager on both mouse + touch input.
7374
* - `mousedown` is eager on mouse input, but lazy on touch input.
7475
* - `click` is lazy on both mouse + touch input.
7576
* @default 'pointerdown'
7677
*/
77-
referencePressEvent?: "pointerdown" | "mousedown" | "click";
78+
referencePressEvent?: MaybeGetter<"pointerdown" | "mousedown" | "click">;
7879
/**
7980
* Whether to dismiss the floating element upon pressing outside of the
8081
* floating element.
@@ -96,38 +97,46 @@ interface UseDismissOptions {
9697
* - `click` is lazy on both mouse + touch input.
9798
* @default 'pointerdown'
9899
*/
99-
outsidePressEvent?: "pointerdown" | "mousedown" | "click";
100+
outsidePressEvent?: MaybeGetter<"pointerdown" | "mousedown" | "click">;
100101
/**
101102
* Whether to dismiss the floating element upon scrolling an overflow
102103
* ancestor.
103104
* @default false
104105
*/
105-
ancestorScroll?: boolean;
106+
ancestorScroll?: MaybeGetter<boolean>;
106107
/**
107108
* Determines whether event listeners bubble upwards through a tree of
108109
* floating elements.
109110
*/
110-
bubbles?: boolean | { escapeKey?: boolean; outsidePress?: boolean };
111+
bubbles?: MaybeGetter<
112+
boolean | { escapeKey?: boolean; outsidePress?: boolean }
113+
>;
111114
/**
112115
* Determines whether to use capture phase event listeners.
113116
*/
114-
capture?: boolean | { escapeKey?: boolean; outsidePress?: boolean };
117+
capture?: MaybeGetter<
118+
boolean | { escapeKey?: boolean; outsidePress?: boolean }
119+
>;
115120
}
116121

117122
class DismissInteraction {
118-
#enabled = $derived.by(() => this.options.enabled ?? true);
119-
#escapeKey = $derived.by(() => this.options.escapeKey ?? true);
123+
#enabled = $derived.by(() => extract(this.options.enabled, true));
124+
#escapeKey = $derived.by(() => extract(this.options.escapeKey, true));
120125
#unstable_outsidePress = $derived.by(() => this.options.outsidePress ?? true);
121-
#outsidePressEvent = $derived.by(
122-
() => this.options.outsidePressEvent ?? "pointerdown",
126+
#outsidePressEvent = $derived.by(() =>
127+
extract(this.options.outsidePressEvent, "pointerdown"),
123128
);
124-
#referencePress = $derived.by(() => this.options.referencePress ?? false);
125-
#referencePressEvent = $derived.by(
126-
() => this.options.referencePressEvent ?? "pointerdown",
129+
#referencePress = $derived.by(() =>
130+
extract(this.options.referencePress, false),
127131
);
128-
#ancestorScroll = $derived.by(() => this.options.ancestorScroll ?? false);
129-
#bubbles = $derived.by(() => this.options.bubbles);
130-
#capture = $derived.by(() => this.options.capture);
132+
#referencePressEvent = $derived.by(() =>
133+
extract(this.options.referencePressEvent, "pointerdown"),
134+
);
135+
#ancestorScroll = $derived.by(() =>
136+
extract(this.options.ancestorScroll, false),
137+
);
138+
#bubbles = $derived.by(() => extract(this.options.bubbles));
139+
#capture = $derived.by(() => extract(this.options.capture));
131140

132141
#outsidePressFn = $derived.by(() =>
133142
typeof this.#unstable_outsidePress === "function"
@@ -184,7 +193,7 @@ class DismissInteraction {
184193
);
185194
};
186195

187-
const doc = getDocument(this.context.elements.floating);
196+
const doc = getDocument(this.context.floating);
188197

189198
const listenersToRemove: Array<() => void> = [];
190199

@@ -217,25 +226,23 @@ class DismissInteraction {
217226
let ancestors: (Element | Window | VisualViewport)[] = [];
218227

219228
if (this.#ancestorScroll) {
220-
if (isElement(this.context.elements.domReference)) {
221-
ancestors = getOverflowAncestors(this.context.elements.domReference);
229+
if (isElement(this.context.domReference)) {
230+
ancestors = getOverflowAncestors(this.context.domReference);
222231
}
223232

224-
if (isElement(this.context.elements.floating)) {
233+
if (isElement(this.context.floating)) {
225234
ancestors = ancestors.concat(
226-
getOverflowAncestors(this.context.elements.floating),
235+
getOverflowAncestors(this.context.floating),
227236
);
228237
}
229238

230239
if (
231-
!isElement(this.context.elements.reference) &&
232-
this.context.elements.reference &&
233-
this.context.elements.reference.contextElement
240+
!isElement(this.context.reference) &&
241+
this.context.reference &&
242+
this.context.reference.contextElement
234243
) {
235244
ancestors = ancestors.concat(
236-
getOverflowAncestors(
237-
this.context.elements.reference.contextElement,
238-
),
245+
getOverflowAncestors(this.context.reference.contextElement),
239246
);
240247
}
241248
}
@@ -335,9 +342,9 @@ class DismissInteraction {
335342

336343
const target = getTarget(event);
337344
const inertSelector = `[${createAttribute("inert")}]`;
338-
const markers = getDocument(
339-
this.context.elements.floating,
340-
).querySelectorAll(inertSelector);
345+
const markers = getDocument(this.context.floating).querySelectorAll(
346+
inertSelector,
347+
);
341348

342349
let targetRootAncestor = isElement(target) ? target : null;
343350

@@ -355,7 +362,7 @@ class DismissInteraction {
355362
isElement(target) &&
356363
!isRootElement(target) &&
357364
// Clicked on a direct ancestor (e.g. FloatingOverlay).
358-
!contains(target, this.context.elements.floating) &&
365+
!contains(target, this.context.floating) &&
359366
// If the target root element contains none of the markers, then the
360367
// element was injected after the floating element rendered.
361368
Array.from(markers).every(
@@ -412,12 +419,12 @@ class DismissInteraction {
412419
const targetIsInsideChildren =
413420
children.length &&
414421
children.some((node) =>
415-
isEventTargetWithin(event, node.context?.elements.floating),
422+
isEventTargetWithin(event, node.context?.floating),
416423
);
417424

418425
if (
419-
isEventTargetWithin(event, this.context.elements.floating) ||
420-
isEventTargetWithin(event, this.context.elements.domReference) ||
426+
isEventTargetWithin(event, this.context.floating) ||
427+
isEventTargetWithin(event, this.context.domReference) ||
421428
targetIsInsideChildren
422429
) {
423430
return;

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

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ class FloatingRootContextOptions {
4545
#stableFloating = $state<HTMLElement | null>(null);
4646
reference: WritableBox<Element | null>;
4747
floating: WritableBox<HTMLElement | null>;
48+
floatingProp = $derived.by(() => extract(this.options.floating, null));
49+
referenceProp = $derived.by(() => extract(this.options.reference, null));
4850

49-
constructor(options: UseFloatingRootContextOptions) {
50-
const floatingProp = $derived.by(() => extract(options.floating, null));
51-
const referenceProp = $derived.by(() => extract(options.reference, null));
51+
constructor(readonly options: UseFloatingRootContextOptions) {
5252
this.open = box.with(() => extract(options.open, false));
5353
this.onOpenChange = options.onOpenChange ?? noop;
5454
this.onReferenceChange = options.onReferenceChange ?? noop;
@@ -68,15 +68,20 @@ class FloatingRootContextOptions {
6868
},
6969
);
7070

71-
this.reference.current = referenceProp;
72-
this.floating.current = floatingProp;
71+
this.reference.current = this.referenceProp;
72+
this.floating.current = this.floatingProp;
7373

7474
$effect.pre(() => {
75-
this.reference.current = referenceProp;
75+
console.log("REFERENCE IN FLOATING ROOT", this.reference.current);
76+
console.log("REFERENCE PROP IN FLOATING ROOT", this.referenceProp);
7677
});
7778

7879
$effect.pre(() => {
79-
this.floating.current = floatingProp;
80+
this.reference.current = this.referenceProp;
81+
});
82+
83+
$effect.pre(() => {
84+
this.floating.current = this.floatingProp;
8085
});
8186
}
8287
}

0 commit comments

Comments
 (0)