Skip to content

Commit

Permalink
next: Dialog (#510)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Apr 25, 2024
1 parent adbcb53 commit 7e293ff
Show file tree
Hide file tree
Showing 44 changed files with 714 additions and 718 deletions.
Original file line number Diff line number Diff line change
@@ -1,38 +1,19 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { getCtx } from "../ctx.js";
import type { CloseEvents, CloseProps } from "../index.js";
import { createDispatcher } from "$lib/internal/events.js";
import { setDialogCloseState } from "../dialog.svelte.js";
import type { CloseProps } from "../index.js";
import { mergeProps } from "$lib/internal/mergeProps.js";
type $$Props = CloseProps;
type $$Events = CloseEvents;
let { asChild, children, child, el = $bindable(), ...restProps }: CloseProps = $props();
export let asChild: $$Props["asChild"] = false;
export let el: $$Props["el"] = undefined;
const state = setDialogCloseState();
const {
elements: { close },
getAttrs,
} = getCtx();
const dispatch = createDispatcher();
const attrs = getAttrs("close");
$: builder = $close;
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props));
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<button
bind:this={el}
use:melt={builder}
type="button"
{...$$restProps}
on:m-click={dispatch}
on:m-keydown={dispatch}
>
<slot {builder} />
<button {...mergedProps} bind:this={el}>
{@render children?.()}
</button>
{/if}
202 changes: 86 additions & 116 deletions packages/bits-ui/src/lib/bits/dialog/components/dialog-content.svelte
Original file line number Diff line number Diff line change
@@ -1,122 +1,92 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { getCtx } from "../ctx.js";
import type { ContentEvents, ContentProps } from "../index.js";
import type { Transition } from "$lib/internal/index.js";
import { setDialogContentState } from "../dialog.svelte.js";
import type { ContentProps } from "../index.js";
import DismissableLayer from "$lib/bits/utilities/dismissable-layer/dismissable-layer.svelte";
import EscapeLayer from "$lib/bits/utilities/escape-layer/escape-layer.svelte";
import FocusScope from "$lib/bits/utilities/focus-scope/focus-scope.svelte";
import PresenceLayer from "$lib/bits/utilities/presence-layer/presence-layer.svelte";
import TextSelectionLayer from "$lib/bits/utilities/text-selection-layer/text-selection-layer.svelte";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/mergeProps.js";
import { useId } from "$lib/internal/useId.svelte.js";
import { noop } from "$lib/internal/callbacks.js";
import ScrollLock from "$lib/bits/utilities/scroll-lock/scroll-lock.svelte";
type T = $$Generic<Transition>;
type In = $$Generic<Transition>;
type Out = $$Generic<Transition>;
let {
id = useId(),
asChild,
children,
child,
el = $bindable(),
forceMount = false,
onDestroyAutoFocus = noop,
onEscapeKeydown = noop,
onInteractOutside = noop,
...restProps
}: ContentProps = $props();
type $$Props = ContentProps<T, In, Out>;
type $$Events = ContentEvents;
const state = setDialogContentState({
id: readonlyBox(() => id),
});
export let transition: $$Props["transition"] = undefined;
export let transitionConfig: $$Props["transitionConfig"] = undefined;
export let inTransition: $$Props["inTransition"] = undefined;
export let inTransitionConfig: $$Props["inTransitionConfig"] = undefined;
export let outTransition: $$Props["outTransition"] = undefined;
export let outTransitionConfig: $$Props["outTransitionConfig"] = undefined;
export let asChild: $$Props["asChild"] = false;
export let id: $$Props["id"] = undefined;
export let el: $$Props["el"] = undefined;
const {
elements: { content },
states: { open },
ids,
getAttrs,
} = getCtx();
const attrs = getAttrs("content");
$: if (id) {
ids.content.set(id);
}
$: builder = $content;
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props));
</script>

{#if asChild && $open}
<slot {builder} />
{:else if transition && $open}
<div
bind:this={el}
transition:transition={transitionConfig}
use:melt={builder}
{...$$restProps}
on:pointerdown
on:pointermove
on:pointerup
on:touchend
on:touchstart
on:touchcancel
on:touchmove
>
<slot {builder} />
</div>
{:else if inTransition && outTransition && $open}
<div
bind:this={el}
in:inTransition={inTransitionConfig}
out:outTransition={outTransitionConfig}
use:melt={builder}
on:pointerdown
on:pointermove
on:pointerup
on:touchend
on:touchstart
on:touchcancel
on:touchmove
{...$$restProps}
>
<slot {builder} />
</div>
{:else if inTransition && $open}
<div
bind:this={el}
in:inTransition={inTransitionConfig}
use:melt={builder}
on:pointerdown
on:pointermove
on:pointerup
on:touchend
on:touchstart
on:touchcancel
on:touchmove
{...$$restProps}
>
<slot {builder} />
</div>
{:else if outTransition && $open}
<div
bind:this={el}
out:outTransition={outTransitionConfig}
use:melt={builder}
on:pointerdown
on:pointermove
on:pointerup
on:touchend
on:touchstart
on:touchcancel
on:touchmove
{...$$restProps}
>
<slot {builder} />
</div>
{:else if $open}
<div
bind:this={el}
use:melt={builder}
on:pointerdown
on:pointermove
on:pointerup
on:touchend
on:touchstart
on:touchcancel
on:touchmove
{...$$restProps}
>
<slot {builder} />
</div>
{/if}
<PresenceLayer {...mergedProps} present={state.root.open.value || forceMount}>
{#snippet presence({ present })}
<ScrollLock {...mergedProps} />
<FocusScope
loop
trapped={present.value}
{...mergedProps}
onDestroyAutoFocus={(e) => {
onDestroyAutoFocus(e);
if (e.defaultPrevented) return;
state.root.triggerNode?.value?.focus();
}}
>
{#snippet focusScope({ props: focusScopeProps })}
<EscapeLayer
{...mergedProps}
present={present.value}
onEscapeKeydown={(e) => {
onEscapeKeydown(e);
state.root.closeDialog();
}}
>
<DismissableLayer
{...mergedProps}
present={present.value}
onInteractOutside={(e) => {
onInteractOutside(e);
if (e.defaultPrevented) return;
state.root.closeDialog();
}}
>
<TextSelectionLayer {...mergedProps} present={present.value}>
{#if asChild}
{@render child?.({
props: mergeProps(mergedProps, focusScopeProps, {
hidden: !present.value,
}),
})}
{:else}
<div
{...mergeProps(mergedProps, focusScopeProps, {
hidden: !present.value,
style: {
pointerEvents: "auto",
},
})}
bind:this={el}
>
{@render children?.()}
</div>
{/if}
</TextSelectionLayer>
</DismissableLayer>
</EscapeLayer>
{/snippet}
</FocusScope>
{/snippet}
</PresenceLayer>
Original file line number Diff line number Diff line change
@@ -1,32 +1,30 @@
<script lang="ts">
import { melt } from "@melt-ui/svelte";
import { getCtx } from "../ctx.js";
import { setDialogDescriptionState } from "../dialog.svelte.js";
import type { DescriptionProps } from "../index.js";
import { readonlyBox } from "$lib/internal/box.svelte.js";
import { mergeProps } from "$lib/internal/mergeProps.js";
import { useId } from "$lib/internal/useId.svelte.js";
type $$Props = DescriptionProps;
let {
id = useId(),
asChild,
children,
child,
el = $bindable(),
...restProps
}: DescriptionProps = $props();
export let asChild: $$Props["asChild"] = false;
export let id: $$Props["id"] = undefined;
export let el: $$Props["el"] = undefined;
const state = setDialogDescriptionState({
id: readonlyBox(() => id),
});
const {
elements: { description },
ids,
getAttrs,
} = getCtx();
const attrs = getAttrs("description");
$: if (id) {
ids.description.set(id);
}
$: builder = $description;
$: Object.assign(builder, attrs);
const mergedProps = $derived(mergeProps(restProps, state.props));
</script>

{#if asChild}
<slot {builder} />
{@render child?.({ props: mergedProps })}
{:else}
<div bind:this={el} use:melt={builder} {...$$restProps}>
<slot {builder} />
<div {...mergedProps} bind:this={el}>
{@render children?.()}
</div>
{/if}
Loading

0 comments on commit 7e293ff

Please sign in to comment.