Skip to content

Commit

Permalink
more
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte committed Dec 15, 2024
1 parent d2314e1 commit a1afad5
Show file tree
Hide file tree
Showing 13 changed files with 260 additions and 135 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,69 @@
<script lang="ts">
import { box, mergeProps } from "svelte-toolbelt";
import type { NavigationMenuContentProps } from "../types.js";
import { useNavigationMenuContentImpl } from "../navigation-menu.svelte.js";
import { noop } from "$lib/internal/noop.js";
import { useId } from "$lib/internal/use-id.js";
import DismissibleLayer from "$lib/bits/utilities/dismissible-layer/dismissible-layer.svelte";
import EscapeLayer from "$lib/bits/utilities/escape-layer/escape-layer.svelte";
let {
ref = $bindable(null),
id = useId(),
child,
children: childrenProp,
onInteractOutside = noop,
onFocusOutside = noop,
onEscapeKeydown = noop,
escapeKeydownBehavior = "close",
interactOutsideBehavior = "close",
...restProps
}: NavigationMenuContentProps = $props();
const contentImplState = useNavigationMenuContentImpl({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => (ref = v)
),
});
const mergedProps = $derived(mergeProps(restProps, contentImplState.props));
</script>

<DismissibleLayer
{id}
enabled={true}
onInteractOutside={(e) => {
onInteractOutside(e);
if (e.defaultPrevented) return;
contentImplState.onInteractOutside(e);
}}
onFocusOutside={(e) => {
onFocusOutside(e);
if (e.defaultPrevented) return;
contentImplState.onFocusOutside(e);
}}
{interactOutsideBehavior}
>
{#snippet children({ props: dismissibleProps })}
<EscapeLayer
enabled={true}
onEscapeKeydown={(e) => {
onEscapeKeydown(e);
if (e.defaultPrevented) return;
contentImplState.onEscapeKeydown(e);
}}
{escapeKeydownBehavior}
>
{@const finalProps = mergeProps(mergedProps, dismissibleProps)}
{#if child}
{@render child({ props: finalProps })}
{:else}
<div {...finalProps}>
{@render childrenProp?.()}
</div>
{/if}
</EscapeLayer>
{/snippet}
</DismissibleLayer>
Original file line number Diff line number Diff line change
@@ -1,82 +1,38 @@
<script lang="ts">
import { box, mergeProps } from "svelte-toolbelt";
import type { NavigationMenuContentProps } from "../types.js";
import { useNavigationMenuContent } from "../navigation-menu.svelte.js";
import { useId } from "$lib/internal/use-id.js";
import Portal from "$lib/bits/utilities/portal/portal.svelte";
import NavigationMenuContentImpl from "./navigation-menu-content-impl.svelte";
import NavigationMenuViewportContentMounter from "./navigation-menu-viewport-content-mounter.svelte";
import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
import DismissibleLayer from "$lib/bits/utilities/dismissible-layer/dismissible-layer.svelte";
import EscapeLayer from "$lib/bits/utilities/escape-layer/escape-layer.svelte";
import Mounted from "$lib/bits/utilities/mounted.svelte";
import { useId } from "$lib/internal/use-id.js";
import type { NavigationMenuContentProps } from "$lib/types.js";
let {
children: contentChildren,
child,
ref = $bindable(null),
id = useId(),
forceMount = false,
onEscapeKeydown,
onInteractOutside,
onFocusOutside,
children,
child,
...restProps
}: NavigationMenuContentProps = $props();
let isMounted = $state(false);
const contentState = useNavigationMenuContent({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => {
ref = v;
}
(v) => (ref = v)
),
forceMount: box.with(() => forceMount),
isMounted: box.with(() => isMounted),
});
const mergedProps = $derived(mergeProps(restProps, contentState.props));
const portalDisabled = $derived(!contentState.menu.viewportNode);
</script>

<Portal to={contentState.menu.viewportNode ?? undefined} disabled={portalDisabled}>
<PresenceLayer {id} present={contentState.isPresent}>
{#if !contentState.context.viewportRef.current}
<PresenceLayer {id} present={forceMount || contentState.open}>
{#snippet presence()}
<EscapeLayer
enabled={contentState.isPresent}
onEscapeKeydown={(e) => {
onEscapeKeydown?.(e);
if (e.defaultPrevented) return;
contentState.onEscapeKeydown(e);
}}
>
<DismissibleLayer
enabled={contentState.isPresent}
{id}
onInteractOutside={(e) => {
onInteractOutside?.(e);
if (e.defaultPrevented) return;
contentState.onInteractOutside(e);
}}
onFocusOutside={(e) => {
onFocusOutside?.(e);
if (e.defaultPrevented) return;
contentState.onFocusOutside(e);
}}
>
{#snippet children({ props: dismissibleProps })}
{#if child}
<Mounted bind:isMounted />
{@render child({ props: mergeProps(dismissibleProps, mergedProps) })}
{:else}
<Mounted bind:isMounted />
<div {...mergeProps(dismissibleProps, mergedProps)}>
{@render contentChildren?.()}
</div>
{/if}
{/snippet}
</DismissibleLayer>
</EscapeLayer>
<NavigationMenuContentImpl {...mergedProps} {children} {child} />
{/snippet}
</PresenceLayer>
</Portal>
{:else}
<NavigationMenuViewportContentMounter />
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<script lang="ts">
import { box, mergeProps } from "svelte-toolbelt";
import type { NavigationMenuIndicatorProps } from "../types.js";
import { useNavigationMenuIndicatorImpl } from "../navigation-menu.svelte.js";
import { useId } from "$lib/internal/use-id.js";
let {
id = useId(),
ref = $bindable(null),
children,
child,
...restProps
}: NavigationMenuIndicatorProps = $props();
const indicatorState = useNavigationMenuIndicatorImpl({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => (ref = v)
),
});
const mergedProps = $derived(mergeProps(restProps, indicatorState.props));
</script>

{#if indicatorState.position}
{#if child}
{@render child({ props: mergedProps })}
{:else}
<div {...mergedProps}>
{@render children?.()}
</div>
{/if}
{/if}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
<script lang="ts">
import { box, mergeProps } from "svelte-toolbelt";
import { mergeProps } from "svelte-toolbelt";
import type { NavigationMenuIndicatorProps } from "../types.js";
import { useNavigationMenuIndicator } from "../navigation-menu.svelte.js";
import NavigationMenuIndicatorImpl from "./navigation-menu-indicator-impl.svelte";
import { useId } from "$lib/internal/use-id.js";
import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
import Portal from "$lib/bits/utilities/portal/portal.svelte";
Expand All @@ -15,28 +16,15 @@
...restProps
}: NavigationMenuIndicatorProps = $props();
const indicatorState = useNavigationMenuIndicator({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => (ref = v)
),
});
const mergedProps = $derived(mergeProps(restProps, indicatorState.props));
const indicatorState = useNavigationMenuIndicator();
const mergedProps = $derived(mergeProps(restProps));
</script>

{#if indicatorState.menu.indicatorTrackNode}
<Portal to={indicatorState.menu.indicatorTrackNode}>
{#if indicatorState.context.indicatorTrackRef.current}
<Portal to={indicatorState.context.indicatorTrackRef.current}>
<PresenceLayer {id} present={forceMount || indicatorState.isVisible}>
{#snippet presence()}
{#if child}
{@render child({ props: mergedProps })}
{:else}
<div {...mergedProps}>
{@render children?.()}
</div>
{/if}
<NavigationMenuIndicatorImpl {...mergedProps} {children} {child} {id} bind:ref />
{/snippet}
</PresenceLayer>
</Portal>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,18 @@
() => ref,
(v) => (ref = v)
),
indicatorTrackRef: box(null),
});
const mergedProps = $derived(mergeProps(restProps, listState.props));
const indicatorTrackProps = $derived(mergeProps(listState.indicatorTrackProps, {}));
const wrapperProps = $derived(mergeProps(listState.wrapperProps));
</script>

<div {...indicatorTrackProps}>
{#if child}
{@render child({ props: mergedProps })}
{:else}
{#if child}
{@render child({ props: mergedProps, wrapperProps })}
{:else}
<div {...wrapperProps}>
<ul {...mergedProps}>
{@render children?.()}
</ul>
{/if}
</div>
</div>
{/if}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<script lang="ts">
import { useNavigationMenuViewportContentMounter } from "../navigation-menu.svelte.js";
useNavigationMenuViewportContentMounter();
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<script lang="ts">
import { box, mergeProps } from "svelte-toolbelt";
import type { NavigationMenuViewportProps } from "../types.js";
import { useNavigationMenuViewportImpl } from "../navigation-menu.svelte.js";
import NavigationMenuContentImpl from "./navigation-menu-content-impl.svelte";
import { useId } from "$lib/internal/use-id.js";
import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
let {
id = useId(),
ref = $bindable(null),
forceMount = false,
...restProps
}: NavigationMenuViewportProps = $props();
const viewportState = useNavigationMenuViewportImpl({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => (ref = v)
),
});
const mergedProps = $derived(mergeProps(restProps, viewportState.props));
</script>

<div {...mergedProps}>
{#each Array.from(viewportState.context.viewportContent) as [value, item]}
{@const isActive = viewportState.activeContentValue === value}
<PresenceLayer id={item.id.current} present={forceMount || isActive}>
{#snippet presence()}
<NavigationMenuContentImpl {...item.props} />
{/snippet}
</PresenceLayer>
{/each}
</div>
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { box, mergeProps } from "svelte-toolbelt";
import type { NavigationMenuViewportProps } from "../types.js";
import { useNavigationMenuViewport } from "../navigation-menu.svelte.js";
import NavigationMenuViewportImpl from "./navigation-menu-viewport-impl.svelte";
import { useId } from "$lib/internal/use-id.js";
import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
Expand All @@ -14,25 +14,11 @@
...restProps
}: NavigationMenuViewportProps = $props();
const viewportState = useNavigationMenuViewport({
id: box.with(() => id),
ref: box.with(
() => ref,
(v) => (ref = v)
),
});
const mergedProps = $derived(mergeProps(restProps, viewportState.props));
const viewportState = useNavigationMenuViewport();
</script>

<PresenceLayer {id} present={forceMount || viewportState.open}>
{#snippet presence()}
{#if child}
{@render child({ props: mergedProps })}
{:else}
<div {...mergedProps}>
{@render children?.()}
</div>
{/if}
<NavigationMenuViewportImpl {children} {child} {forceMount} {id} bind:ref {...restProps} />
{/snippet}
</PresenceLayer>
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
value: box.with(
() => value,
(v) => {
rootState.handleValueChange(v);
if (controlledValue) {
onValueChange(v);
} else {
Expand Down
Loading

0 comments on commit a1afad5

Please sign in to comment.