Skip to content

Commit 25df757

Browse files
authored
chore: simplify internals (#1853)
1 parent 42e85b7 commit 25df757

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+407
-317
lines changed

.changeset/chilly-crabs-fold.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"bits-ui": patch
3+
---
4+
5+
chore: simplify internals

docs/src/lib/components/demos/tooltip-demo-custom-anchor.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@
1515
>
1616
<MagicWand class="size-5" />
1717
</Tooltip.Trigger>
18-
<Tooltip.Content sideOffset={8} {customAnchor}>
18+
<Tooltip.Content
19+
sideOffset={8}
20+
{customAnchor}
21+
class="animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-tooltip-content-transform-origin)"
22+
>
1923
<div
2024
class="rounded-input border-dark-10 bg-background shadow-popover outline-hidden z-0 flex items-center justify-center border p-3 text-sm font-medium"
2125
>

docs/src/lib/components/demos/tooltip-demo-custom.svelte

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
>
2020
<MagicWand class="size-5" />
2121
</Tooltip.Trigger>
22-
<Tooltip.Content {...contentProps}>
22+
<Tooltip.Content
23+
{...contentProps}
24+
class="animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-tooltip-content-transform-origin)"
25+
>
2326
<div>
2427
<Tooltip.Arrow
2528
class="border-dark-10 text-dark-10 rounded-[2px] border-l border-t"

docs/src/lib/components/demos/tooltip-demo-group.svelte

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
{#snippet tooltipContent({ content }: { content: string })}
1616
<Tooltip.Content
17-
class="rounded-input border-dark-10 bg-background shadow-popover outline-hidden z-0 flex items-center justify-center border p-3 text-sm font-medium"
17+
class="rounded-input border-dark-10 bg-background shadow-popover outline-hidden animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-tooltip-content-transform-origin) z-0 flex items-center justify-center border p-3 text-sm font-medium"
1818
sideOffset={8}
1919
>
2020
{content}

docs/src/lib/components/demos/tooltip-demo.svelte

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
1111
>
1212
<MagicWand class="size-5" />
1313
</Tooltip.Trigger>
14-
<Tooltip.Content sideOffset={8}>
14+
<Tooltip.Content
15+
sideOffset={8}
16+
class="animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-(--bits-tooltip-content-transform-origin)"
17+
>
1518
<div
1619
class="rounded-input border-dark-10 bg-background shadow-popover outline-hidden z-0 flex items-center justify-center border p-3 text-sm font-medium"
1720
>

packages/bits-ui/src/lib/bits/accordion/accordion.svelte.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
afterTick,
33
attachRef,
4+
boxWith,
45
type Box,
56
type ReadableBoxedValues,
67
type WritableBoxedValues,
@@ -18,6 +19,7 @@ import type { Orientation } from "$lib/shared/index.js";
1819
import { createBitsAttrs } from "$lib/internal/attrs.js";
1920
import { RovingFocusGroup } from "$lib/internal/roving-focus-group.js";
2021
import { on } from "svelte/events";
22+
import { PresenceManager } from "$lib/internal/presence-manager.svelte.js";
2123

2224
const accordionAttrs = createBitsAttrs({
2325
component: "accordion",
@@ -183,12 +185,19 @@ export class AccordionItemState {
183185
() => this.opts.disabled.current || this.root.opts.disabled.current
184186
);
185187
readonly attachment: RefAttachment;
188+
contentNode = $state<HTMLElement | null>(null);
189+
contentPresence: PresenceManager;
186190

187191
constructor(opts: AccordionItemStateOpts) {
188192
this.opts = opts;
189193
this.root = opts.rootState;
190194
this.updateValue = this.updateValue.bind(this);
191195
this.attachment = attachRef(this.opts.ref);
196+
197+
this.contentPresence = new PresenceManager({
198+
ref: boxWith(() => this.contentNode),
199+
open: boxWith(() => this.isActive),
200+
});
192201
}
193202

194203
updateValue(): void {
@@ -290,7 +299,7 @@ export class AccordionContentState {
290299
this.opts = opts;
291300
this.item = item;
292301
this.#isMountAnimationPrevented = this.item.isActive;
293-
this.attachment = attachRef(this.opts.ref);
302+
this.attachment = attachRef(this.opts.ref, (v) => (this.item.contentNode = v));
294303
// Prevent mount animations on initial render
295304
$effect(() => {
296305
const rAF = requestAnimationFrame(() => {
@@ -354,6 +363,10 @@ export class AccordionContentState {
354363
});
355364
};
356365

366+
get shouldRender() {
367+
return this.item.contentPresence.shouldRender;
368+
}
369+
357370
readonly snippetProps = $derived.by(() => ({ open: this.item.isActive }));
358371

359372
readonly props = $derived.by(
@@ -372,6 +385,15 @@ export class AccordionContentState {
372385
this.opts.hiddenUntilFound.current && !this.item.isActive
373386
? "until-found"
374387
: undefined,
388+
...(this.opts.hiddenUntilFound.current && !this.shouldRender
389+
? {}
390+
: {
391+
hidden: this.opts.hiddenUntilFound.current
392+
? !this.shouldRender
393+
: this.opts.forceMount.current
394+
? undefined
395+
: !this.shouldRender,
396+
}),
375397
...this.attachment,
376398
}) as const
377399
);

packages/bits-ui/src/lib/bits/accordion/components/accordion-content.svelte

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
import { mergeProps, boxWith } from "svelte-toolbelt";
33
import { AccordionContentState } from "../accordion.svelte.js";
44
import type { AccordionContentProps } from "../types.js";
5-
import { PresenceLayer } from "$lib/bits/utilities/presence-layer/index.js";
65
import { createId } from "$lib/internal/create-id.js";
76
87
const uid = $props.id();
@@ -26,28 +25,17 @@
2625
),
2726
hiddenUntilFound: boxWith(() => hiddenUntilFound),
2827
});
28+
29+
const mergedProps = $derived(mergeProps(restProps, contentState.props));
2930
</script>
3031

31-
<PresenceLayer forceMount={true} open={contentState.open} ref={contentState.opts.ref}>
32-
{#snippet presence({ present })}
33-
{@const mergedProps = mergeProps(
34-
restProps,
35-
contentState.props,
36-
hiddenUntilFound && !present
37-
? {}
38-
: {
39-
hidden: hiddenUntilFound ? !present : forceMount ? undefined : !present,
40-
}
41-
)}
42-
{#if child}
43-
{@render child({
44-
props: mergedProps,
45-
...contentState.snippetProps,
46-
})}
47-
{:else}
48-
<div {...mergedProps}>
49-
{@render children?.()}
50-
</div>
51-
{/if}
52-
{/snippet}
53-
</PresenceLayer>
32+
{#if child}
33+
{@render child({
34+
props: mergedProps,
35+
...contentState.snippetProps,
36+
})}
37+
{:else}
38+
<div {...mergedProps}>
39+
{@render children?.()}
40+
</div>
41+
{/if}

packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-content.svelte

Lines changed: 50 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,11 @@
44
import DismissibleLayer from "$lib/bits/utilities/dismissible-layer/dismissible-layer.svelte";
55
import EscapeLayer from "$lib/bits/utilities/escape-layer/escape-layer.svelte";
66
import FocusScope from "$lib/bits/utilities/focus-scope/focus-scope.svelte";
7-
import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
87
import TextSelectionLayer from "$lib/bits/utilities/text-selection-layer/text-selection-layer.svelte";
98
import { createId } from "$lib/internal/create-id.js";
109
import { noop } from "$lib/internal/noop.js";
1110
import ScrollLock from "$lib/bits/utilities/scroll-lock/scroll-lock.svelte";
1211
import { DialogContentState } from "$lib/bits/dialog/dialog.svelte.js";
13-
import { shouldEnableFocusTrap } from "$lib/internal/should-enable-focus-trap.js";
1412
1513
const uid = $props.id();
1614
@@ -42,74 +40,64 @@
4240
const mergedProps = $derived(mergeProps(restProps, contentState.props));
4341
</script>
4442

45-
<PresenceLayer
46-
{forceMount}
47-
open={contentState.root.opts.open.current || forceMount}
48-
ref={contentState.opts.ref}
49-
>
50-
{#snippet presence()}
51-
<FocusScope
52-
ref={contentState.opts.ref}
53-
loop
54-
{trapFocus}
55-
enabled={shouldEnableFocusTrap({
56-
forceMount,
57-
present: contentState.root.opts.open.current,
58-
open: contentState.root.opts.open.current,
59-
})}
60-
{onCloseAutoFocus}
61-
onOpenAutoFocus={(e) => {
62-
onOpenAutoFocus(e);
63-
if (e.defaultPrevented) return;
64-
e.preventDefault();
65-
afterSleep(0, () => contentState.opts.ref.current?.focus());
66-
}}
67-
>
68-
{#snippet focusScope({ props: focusScopeProps })}
69-
<EscapeLayer
43+
{#if contentState.shouldRender || forceMount}
44+
<FocusScope
45+
ref={contentState.opts.ref}
46+
loop
47+
{trapFocus}
48+
enabled={contentState.root.opts.open.current}
49+
{onCloseAutoFocus}
50+
onOpenAutoFocus={(e) => {
51+
onOpenAutoFocus(e);
52+
if (e.defaultPrevented) return;
53+
e.preventDefault();
54+
afterSleep(0, () => contentState.opts.ref.current?.focus());
55+
}}
56+
>
57+
{#snippet focusScope({ props: focusScopeProps })}
58+
<EscapeLayer
59+
{...mergedProps}
60+
enabled={contentState.root.opts.open.current}
61+
ref={contentState.opts.ref}
62+
onEscapeKeydown={(e) => {
63+
onEscapeKeydown(e);
64+
if (e.defaultPrevented) return;
65+
contentState.root.handleClose();
66+
}}
67+
>
68+
<DismissibleLayer
7069
{...mergedProps}
71-
enabled={contentState.root.opts.open.current}
7270
ref={contentState.opts.ref}
73-
onEscapeKeydown={(e) => {
74-
onEscapeKeydown(e);
71+
enabled={contentState.root.opts.open.current}
72+
{interactOutsideBehavior}
73+
onInteractOutside={(e) => {
74+
onInteractOutside(e);
7575
if (e.defaultPrevented) return;
7676
contentState.root.handleClose();
7777
}}
7878
>
79-
<DismissibleLayer
79+
<TextSelectionLayer
8080
{...mergedProps}
8181
ref={contentState.opts.ref}
8282
enabled={contentState.root.opts.open.current}
83-
{interactOutsideBehavior}
84-
onInteractOutside={(e) => {
85-
onInteractOutside(e);
86-
if (e.defaultPrevented) return;
87-
contentState.root.handleClose();
88-
}}
8983
>
90-
<TextSelectionLayer
91-
{...mergedProps}
92-
ref={contentState.opts.ref}
93-
enabled={contentState.root.opts.open.current}
94-
>
95-
{#if child}
96-
{#if contentState.root.opts.open.current}
97-
<ScrollLock {preventScroll} {restoreScrollDelay} />
98-
{/if}
99-
{@render child({
100-
props: mergeProps(mergedProps, focusScopeProps),
101-
...contentState.snippetProps,
102-
})}
103-
{:else}
104-
<ScrollLock {preventScroll} />
105-
<div {...mergeProps(mergedProps, focusScopeProps)}>
106-
{@render children?.()}
107-
</div>
84+
{#if child}
85+
{#if contentState.root.opts.open.current}
86+
<ScrollLock {preventScroll} {restoreScrollDelay} />
10887
{/if}
109-
</TextSelectionLayer>
110-
</DismissibleLayer>
111-
</EscapeLayer>
112-
{/snippet}
113-
</FocusScope>
114-
{/snippet}
115-
</PresenceLayer>
88+
{@render child({
89+
props: mergeProps(mergedProps, focusScopeProps),
90+
...contentState.snippetProps,
91+
})}
92+
{:else}
93+
<ScrollLock {preventScroll} />
94+
<div {...mergeProps(mergedProps, focusScopeProps)}>
95+
{@render children?.()}
96+
</div>
97+
{/if}
98+
</TextSelectionLayer>
99+
</DismissibleLayer>
100+
</EscapeLayer>
101+
{/snippet}
102+
</FocusScope>
103+
{/if}

packages/bits-ui/src/lib/bits/collapsible/collapsible.svelte.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ import type {
2020
RefAttachment,
2121
WithRefOpts,
2222
} from "$lib/internal/types.js";
23-
import { OpenChangeComplete } from "$lib/internal/open-change-complete.js";
2423
import { on } from "svelte/events";
24+
import { PresenceManager } from "$lib/internal/presence-manager.svelte.js";
2525

2626
const collapsibleAttrs = createBitsAttrs({
2727
component: "collapsible",
@@ -48,14 +48,15 @@ export class CollapsibleRootState {
4848
readonly opts: CollapsibleRootStateOpts;
4949
readonly attachment: RefAttachment;
5050
contentNode = $state<HTMLElement | null>(null);
51+
contentPresence: PresenceManager;
5152
contentId = $state<string | undefined>(undefined);
5253

5354
constructor(opts: CollapsibleRootStateOpts) {
5455
this.opts = opts;
5556
this.toggleOpen = this.toggleOpen.bind(this);
5657
this.attachment = attachRef(this.opts.ref);
5758

58-
new OpenChangeComplete({
59+
this.contentPresence = new PresenceManager({
5960
ref: boxWith(() => this.contentNode),
6061
open: this.opts.open,
6162
onComplete: () => {
@@ -176,6 +177,10 @@ export class CollapsibleContentState {
176177
});
177178
}
178179

180+
get shouldRender() {
181+
return this.root.contentPresence.shouldRender;
182+
}
183+
179184
readonly snippetProps = $derived.by(() => ({
180185
open: this.root.opts.open.current,
181186
}));
@@ -199,6 +204,15 @@ export class CollapsibleContentState {
199204
"data-state": getDataOpenClosed(this.root.opts.open.current),
200205
"data-disabled": boolToEmptyStrOrUndef(this.root.opts.disabled.current),
201206
[collapsibleAttrs.content]: "",
207+
...(this.opts.hiddenUntilFound.current && !this.shouldRender
208+
? {}
209+
: {
210+
hidden: this.opts.hiddenUntilFound.current
211+
? !this.shouldRender
212+
: this.opts.forceMount.current
213+
? undefined
214+
: !this.shouldRender,
215+
}),
202216
...this.attachment,
203217
}) as const
204218
);

0 commit comments

Comments
 (0)