-
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
14 changed files
with
1,277 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
82 changes: 82 additions & 0 deletions
82
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-content.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
<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 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"; | ||
let { | ||
children: contentChildren, | ||
child, | ||
ref = $bindable(null), | ||
id = useId(), | ||
forceMount = false, | ||
onEscapeKeydown, | ||
onInteractOutside, | ||
onFocusOutside, | ||
...restProps | ||
}: NavigationMenuContentProps = $props(); | ||
let isMounted = $state(false); | ||
const contentState = useNavigationMenuContent({ | ||
id: box.with(() => id), | ||
ref: box.with( | ||
() => ref, | ||
(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}> | ||
{#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> | ||
{/snippet} | ||
</PresenceLayer> | ||
</Portal> |
43 changes: 43 additions & 0 deletions
43
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-indicator.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
<script lang="ts"> | ||
import { box, mergeProps } from "svelte-toolbelt"; | ||
import type { NavigationMenuIndicatorProps } from "../types.js"; | ||
import { useNavigationMenuIndicator } from "../navigation-menu.svelte.js"; | ||
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"; | ||
let { | ||
id = useId(), | ||
ref = $bindable(null), | ||
children, | ||
child, | ||
forceMount = false, | ||
...restProps | ||
}: NavigationMenuIndicatorProps = $props(); | ||
const indicatorState = useNavigationMenuIndicator({ | ||
id: box.with(() => id), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
}); | ||
const mergedProps = $derived(mergeProps(restProps, indicatorState.props)); | ||
</script> | ||
|
||
{#if indicatorState.menu.indicatorTrackNode} | ||
<Portal to={indicatorState.menu.indicatorTrackNode}> | ||
<PresenceLayer {id} present={forceMount || indicatorState.isVisible}> | ||
{#snippet presence()} | ||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<div {...mergedProps}> | ||
{@render children?.()} | ||
</div> | ||
{/if} | ||
{/snippet} | ||
</PresenceLayer> | ||
</Portal> | ||
{/if} |
34 changes: 34 additions & 0 deletions
34
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-item.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { NavigationMenuItemProps } from "../types.js"; | ||
import { useNavigationMenuItem } from "../navigation-menu.svelte.js"; | ||
import { useId } from "$lib/internal/use-id.js"; | ||
let { | ||
id = useId(), | ||
value = useId(), | ||
ref = $bindable(null), | ||
child, | ||
children, | ||
...restProps | ||
}: NavigationMenuItemProps = $props(); | ||
const itemState = useNavigationMenuItem({ | ||
id: box.with(() => id), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
value: box.with(() => value), | ||
}); | ||
const mergedProps = $derived(mergeProps(restProps, itemState.props)); | ||
</script> | ||
|
||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<li {...mergedProps}> | ||
{@render children?.()} | ||
</li> | ||
{/if} |
37 changes: 37 additions & 0 deletions
37
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-link.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
<script lang="ts"> | ||
import { box, mergeProps } from "svelte-toolbelt"; | ||
import type { NavigationMenuLinkProps } from "../types.js"; | ||
import { useNavigationMenuLink } from "../navigation-menu.svelte.js"; | ||
import { useId } from "$lib/internal/use-id.js"; | ||
import { noop } from "$lib/internal/noop.js"; | ||
let { | ||
id = useId(), | ||
ref = $bindable(null), | ||
child, | ||
children, | ||
active = false, | ||
onSelect = noop, | ||
...restProps | ||
}: NavigationMenuLinkProps = $props(); | ||
const linkState = useNavigationMenuLink({ | ||
id: box.with(() => id), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
active: box.with(() => active), | ||
onSelect: box.with(() => onSelect), | ||
}); | ||
const mergedProps = $derived(mergeProps(restProps, linkState.props)); | ||
</script> | ||
|
||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<a {...mergedProps}> | ||
{@render children?.()} | ||
</a> | ||
{/if} |
36 changes: 36 additions & 0 deletions
36
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-list.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { NavigationMenuListProps } from "../types.js"; | ||
import { useNavigationMenuList } from "../navigation-menu.svelte.js"; | ||
import { useId } from "$lib/internal/use-id.js"; | ||
let { | ||
id = useId(), | ||
children, | ||
child, | ||
ref = $bindable(null), | ||
...restProps | ||
}: NavigationMenuListProps = $props(); | ||
const listState = useNavigationMenuList({ | ||
id: box.with(() => id), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
indicatorTrackRef: box(null), | ||
}); | ||
const mergedProps = $derived(mergeProps(restProps, listState.props)); | ||
const indicatorTrackProps = $derived(mergeProps(listState.indicatorTrackProps, {})); | ||
</script> | ||
|
||
<div {...indicatorTrackProps}> | ||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<ul {...mergedProps}> | ||
{@render children?.()} | ||
</ul> | ||
{/if} | ||
</div> |
47 changes: 47 additions & 0 deletions
47
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-trigger.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
<script lang="ts"> | ||
import { box, mergeProps } from "svelte-toolbelt"; | ||
import type { NavigationMenuTriggerProps } from "../types.js"; | ||
import { useNavigationMenuTrigger } from "../navigation-menu.svelte.js"; | ||
import { useId } from "$lib/internal/use-id.js"; | ||
import VisuallyHidden from "$lib/bits/utilities/visually-hidden/visually-hidden.svelte"; | ||
import Mounted from "$lib/bits/utilities/mounted.svelte"; | ||
let { | ||
id = useId(), | ||
disabled = false, | ||
children, | ||
child, | ||
ref = $bindable(null), | ||
...restProps | ||
}: NavigationMenuTriggerProps = $props(); | ||
let focusProxyMounted = $state(false); | ||
const triggerState = useNavigationMenuTrigger({ | ||
id: box.with(() => id), | ||
disabled: box.with(() => disabled ?? false), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
focusProxyMounted: box.with(() => focusProxyMounted), | ||
}); | ||
const mergedProps = $derived(mergeProps(restProps, triggerState.props)); | ||
</script> | ||
|
||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<button {...mergedProps}> | ||
{@render children?.()} | ||
</button> | ||
{/if} | ||
|
||
{#if triggerState.open} | ||
<Mounted bind:isMounted={focusProxyMounted} /> | ||
<VisuallyHidden {...triggerState.visuallyHiddenProps} /> | ||
{#if triggerState.menu.viewportNode} | ||
<span aria-owns={triggerState.item.contentNode?.id ?? undefined}></span> | ||
{/if} | ||
{/if} |
38 changes: 38 additions & 0 deletions
38
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu-viewport.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
<script lang="ts"> | ||
import { box, mergeProps } from "svelte-toolbelt"; | ||
import type { NavigationMenuViewportProps } from "../types.js"; | ||
import { useNavigationMenuViewport } from "../navigation-menu.svelte.js"; | ||
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), | ||
children, | ||
child, | ||
forceMount = false, | ||
...restProps | ||
}: NavigationMenuViewportProps = $props(); | ||
const viewportState = useNavigationMenuViewport({ | ||
id: box.with(() => id), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
}); | ||
const mergedProps = $derived(mergeProps(restProps, viewportState.props)); | ||
</script> | ||
|
||
<PresenceLayer {id} present={forceMount || viewportState.open}> | ||
{#snippet presence()} | ||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<div {...mergedProps}> | ||
{@render children?.()} | ||
</div> | ||
{/if} | ||
{/snippet} | ||
</PresenceLayer> |
55 changes: 55 additions & 0 deletions
55
packages/bits-ui/src/lib/bits/navigation-menu-2/components/navigation-menu.svelte
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
<script lang="ts"> | ||
import { box, mergeProps } from "svelte-toolbelt"; | ||
import type { NavigationMenuRootProps } from "../types.js"; | ||
import { useNavigationMenuRoot } from "../navigation-menu.svelte.js"; | ||
import { useId } from "$lib/internal/use-id.js"; | ||
import { noop } from "$lib/internal/noop.js"; | ||
let { | ||
child, | ||
children, | ||
id = useId(), | ||
ref = $bindable(null), | ||
value = $bindable(""), | ||
onValueChange = noop, | ||
delayDuration = 200, | ||
skipDelayDuration = 300, | ||
dir = "ltr", | ||
orientation = "horizontal", | ||
controlledValue = false, | ||
...restProps | ||
}: NavigationMenuRootProps = $props(); | ||
const rootState = useNavigationMenuRoot({ | ||
id: box.with(() => id), | ||
value: box.with( | ||
() => value, | ||
(v) => { | ||
if (controlledValue) { | ||
onValueChange(v); | ||
} else { | ||
value = v; | ||
onValueChange(v); | ||
} | ||
} | ||
), | ||
delayDuration: box.with(() => delayDuration), | ||
skipDelayDuration: box.with(() => skipDelayDuration), | ||
dir: box.with(() => dir), | ||
orientation: box.with(() => orientation), | ||
ref: box.with( | ||
() => ref, | ||
(v) => (ref = v) | ||
), | ||
}); | ||
const mergedProps = $derived(mergeProps({ "aria-label": "main" }, restProps, rootState.props)); | ||
</script> | ||
|
||
{#if child} | ||
{@render child({ props: mergedProps })} | ||
{:else} | ||
<nav {...mergedProps}> | ||
{@render children?.()} | ||
</nav> | ||
{/if} |
Oops, something went wrong.