Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

next: cleanup layers #490

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { getAccordionContentState } from "../accordion.svelte.js";
import type { AccordionContentProps } from "../types.js";
import Presence from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
import Presence from "$lib/bits/utilities/presence/presence.svelte";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { generateId } from "$lib/internal/id.js";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { getCollapsibleContentState } from "../collapsible.svelte.js";
import type { CollapsibleContentProps } from "../types.js";
import Presence from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
import Presence from "$lib/bits/utilities/presence/presence.svelte";
import { generateId } from "$lib/internal/id.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";

Expand All @@ -23,7 +23,7 @@
});
</script>

<Presence forceMount={true} present={content.present} {id}>
<Presence forceMount={true} present={content.present || forceMount} {id}>
{#snippet presence({ present })}
{@const mergedProps = {
...restProps,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@

<PopperLayer.Root
{...restProps}
forceMount={true}
{forceMount}
present={state.root.open.value || forceMount}
{id}
{style}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import {
type ReadonlyBox,
type ReadonlyBoxedValues,
boxedState,
generateId,
readonlyBoxedState,
styleToString,
useNodeById,
} from "$lib/internal/index.js";
Expand All @@ -41,7 +43,6 @@ export type Align = (typeof ALIGN_OPTIONS)[number];
export type Boundary = Element | null;

class FloatingRootState {
wrapperId = undefined as unknown as ReadonlyBox<string>;
contentNode = undefined as unknown as Box<HTMLElement | null>;
anchorNode = undefined as unknown as Box<HTMLElement | null>;
arrowNode = boxedState<HTMLElement | null>(null);
Expand All @@ -62,7 +63,6 @@ class FloatingRootState {

export type FloatingContentStateProps = ReadonlyBoxedValues<{
id: string;
wrapperId: string;
side: Side;
sideOffset: number;
align: Align;
Expand All @@ -84,6 +84,7 @@ export type FloatingContentStateProps = ReadonlyBoxedValues<{
class FloatingContentState {
root = undefined as unknown as FloatingRootState;
id = undefined as unknown as FloatingContentStateProps["id"];
contentId = readonlyBoxedState<string>(generateId());
style = undefined as unknown as FloatingContentStateProps["style"];
dir = undefined as unknown as FloatingContentStateProps["dir"];
side = undefined as unknown as FloatingContentStateProps["side"];
Expand Down Expand Up @@ -171,7 +172,7 @@ class FloatingContentState {
cannotCenterArrow = $derived(this.floating.middlewareData.arrow?.centerOffset !== 0);
contentZIndex = $state<string>();
wrapperProps = $derived({
id: this.root.wrapperId.value,
id: this.id.value,
"data-bits-floating-content-wrapper": "",
style: styleToString({
...this.floating.floatingStyles,
Expand All @@ -192,6 +193,7 @@ class FloatingContentState {
dir: this.dir.value,
} as const);
props = $derived({
id: this.contentId.value,
"data-side": this.placedSide,
"data-align": this.placedAlign,
style: styleToString({
Expand Down Expand Up @@ -222,9 +224,8 @@ class FloatingContentState {
this.root = root;
this.present = props.present;
this.arrowSize = useSize(this.root.arrowNode);
this.root.wrapperId = props.wrapperId;
this.root.wrapperNode = useNodeById(this.root.wrapperId);
this.root.contentNode = useNodeById(this.id);
this.root.wrapperNode = useNodeById(this.id);
this.root.contentNode = useNodeById(this.contentId);
this.floating = useFloating({
strategy: () => this.strategy.value,
placement: () => this.desiredPlacement,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,11 +103,6 @@ export type FloatingLayerContentProps = {
* Whether the floating layer is present.
*/
present: boolean;

/**
* The ID of the content wrapper element.
*/
wrapperId?: string;
};

export type FloatingLayerArrowProps = {
Expand Down
2 changes: 1 addition & 1 deletion packages/bits-ui/src/lib/bits/utilities/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@ export * as FloatingLayer from "./floating-layer/index.js";
export * as EscapeLayer from "./escape-layer/index.js";
export * as DismissableLayer from "./dismissable-layer/index.js";
export * as PreventTextSelectionOverflowLayer from "./prevent-text-selection-overflow-layer/index.js";
export * as PresenceLayer from "./presence-layer/index.js";
export * as PresenceLayer from "./presence/index.js";
export * as PopperLayer from "./popper-layer/index.js";
export * as Portal from "./portal/index.js";
Original file line number Diff line number Diff line change
Expand Up @@ -12,34 +12,28 @@
let { popper, ...restProps }: Props = $props();
</script>

<Portal.Root forceMount={true}>
{#snippet portal({ portalProps })}
<PresenceLayer.Root {...restProps}>
{#snippet presence({ present })}
<FloatingLayer.Content
{...restProps}
wrapperId={portalProps.id}
present={present.value}
>
{#snippet content({ props })}
<EscapeLayer.Root {...restProps} present={present.value}>
<DismissableLayer.Root {...restProps} present={present.value}>
<PreventTextSelectionOverflowLayer.Root
{...restProps}
present={present.value}
>
{@render popper?.({
props: {
...props,
hidden: present.value ? undefined : true,
},
})}
</PreventTextSelectionOverflowLayer.Root>
</DismissableLayer.Root>
</EscapeLayer.Root>
{/snippet}
</FloatingLayer.Content>
{/snippet}
</PresenceLayer.Root>
<PresenceLayer.Root {...restProps}>
{#snippet presence({ present })}
<Portal.Root {...restProps}>
<FloatingLayer.Content {...restProps} present={present.value}>
{#snippet content({ props })}
<EscapeLayer.Root {...restProps} present={present.value}>
<DismissableLayer.Root {...restProps} present={present.value}>
<PreventTextSelectionOverflowLayer.Root
{...restProps}
present={present.value}
>
{@render popper?.({
props: {
...props,
hidden: present.value ? undefined : true,
},
})}
</PreventTextSelectionOverflowLayer.Root>
</DismissableLayer.Root>
</EscapeLayer.Root>
{/snippet}
</FloatingLayer.Content>
</Portal.Root>
{/snippet}
</Portal.Root>
</PresenceLayer.Root>
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { EscapeLayerProps } from "../escape-layer/types.js";
import type { DismissableLayerProps } from "../dismissable-layer/types.js";
import type { FloatingLayerContentProps } from "../floating-layer/types.js";
import type { PreventTextSelectionOverflowLayerProps } from "../prevent-text-selection-overflow-layer/types.js";
import type { PresenceLayerProps } from "../presence-layer/types.js";
import type { PresenceLayerProps } from "../presence/types.js";

export type PopperLayerProps = EscapeLayerProps &
DismissableLayerProps &
Expand Down
11 changes: 7 additions & 4 deletions packages/bits-ui/src/lib/bits/utilities/portal/portal.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@
import type { PortalProps } from "./types.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { generateId } from "$lib/internal/id.js";
import { useMounted } from "$lib/internal/use-mounted.svelte.js";

let { id = generateId(), to = "body", forceMount, portal }: PortalProps = $props();
let { id = generateId(), to = "body", forceMount, children }: PortalProps = $props();

const state = usePortal(
usePortal(
readonlyBox(() => id),
readonlyBox(() => to)
);

const mounted = useMounted();
</script>

{#if forceMount}
{@render portal?.({ portalProps: state.props })}
{#if forceMount || mounted.value}
{@render children?.()}
{/if}
2 changes: 1 addition & 1 deletion packages/bits-ui/src/lib/bits/utilities/portal/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,5 @@ export type PortalProps = {
*/
id?: string;

portal?: Snippet<[{ portalProps: { id: string; "data-portal": string } }]>;
children?: Snippet;
};
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export { default as Root } from "./presence-layer.svelte";
export { default as Root } from "./presence.svelte";

export type { PresenceLayerProps as Props } from "./types.js";
17 changes: 17 additions & 0 deletions packages/bits-ui/src/lib/internal/use-mounted.svelte.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { untrack } from "svelte";

export function useMounted() {
let mounted = $state(false);
$effect(() => {
untrack(() => (mounted = true));
return () => {
untrack(() => (mounted = false));
};
});

return {
get value() {
return mounted;
},
};
}
Loading