From 6c387940ca2e46ec8c226eb0df2d472431e325b1 Mon Sep 17 00:00:00 2001 From: Hunter Johnston <64506580+huntabyte@users.noreply.github.com> Date: Mon, 17 Jun 2024 17:39:33 -0400 Subject: [PATCH] next: alert dialog (#578) --- .../components/alert-dialog-action.svelte | 38 ---- .../components/alert-dialog-cancel.svelte | 52 +++-- .../components/alert-dialog-content.svelte | 200 ++++++++---------- .../alert-dialog-description.svelte | 33 --- .../components/alert-dialog-overlay.svelte | 62 ------ .../components/alert-dialog-portal.svelte | 27 --- .../components/alert-dialog-title.svelte | 35 --- .../components/alert-dialog-trigger.svelte | 38 ---- .../components/alert-dialog.svelte | 61 ------ .../src/lib/bits/alert-dialog/index.ts | 19 +- .../src/lib/bits/alert-dialog/types.ts | 128 +++-------- .../src/lib/bits/dialog/dialog.svelte.ts | 47 ++++ packages/bits-ui/src/lib/internal/index.ts | 2 +- .../components/demos/alert-dialog-demo.svelte | 9 +- 14 files changed, 193 insertions(+), 558 deletions(-) delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-action.svelte delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-description.svelte delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-overlay.svelte delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-portal.svelte delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-title.svelte delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-trigger.svelte delete mode 100644 packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog.svelte diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-action.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-action.svelte deleted file mode 100644 index f8cacf244..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-action.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - -{#if asChild} - -{:else} - - - -{/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-cancel.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-cancel.svelte index 6ff180ddc..4ffca64a9 100644 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-cancel.svelte +++ b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-cancel.svelte @@ -1,38 +1,34 @@ {#if asChild} - + {@render child?.({ props: mergedProps })} {:else} - - + + {@render children?.()} {/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-content.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-content.svelte index 4b453c23e..01075395e 100644 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-content.svelte +++ b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-content.svelte @@ -1,121 +1,93 @@ -{#if asChild && $open} - -{:else if transition && $open} - - - -{:else if inTransition && outTransition && $open} - - - -{:else if inTransition && $open} - - - -{:else if outTransition && $open} - - - -{:else if $open} - - - -{/if} + + {#snippet presence({ present })} + + { + onDestroyAutoFocus(e); + if (e.defaultPrevented) return; + contentState.root.triggerNode?.focus(); + }} + onMountAutoFocus={(e) => { + onMountAutoFocus(e); + if (e.defaultPrevented) return; + e.preventDefault(); + contentState.root.cancelNode?.focus(); + }} + > + {#snippet focusScope({ props: focusScopeProps })} + { + onEscapeKeydown(e); + contentState.root.closeDialog(); + }} + > + + + {#if asChild} + {@render child?.({ + props: mergeProps(mergedProps, focusScopeProps, { + hidden: !present.value, + }), + })} + {:else} + + {@render children?.()} + + {/if} + + + + {/snippet} + + {/snippet} + diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-description.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-description.svelte deleted file mode 100644 index befd5e63e..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-description.svelte +++ /dev/null @@ -1,33 +0,0 @@ - - -{#if asChild} - -{:else} - - - -{/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-overlay.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-overlay.svelte deleted file mode 100644 index b43029aad..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-overlay.svelte +++ /dev/null @@ -1,62 +0,0 @@ - - -{#if asChild && $open} - -{:else if transition && $open} - -{:else if inTransition && outTransition && $open} - -{:else if inTransition && $open} - -{:else if outTransition && $open} - -{:else if $open} - -{/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-portal.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-portal.svelte deleted file mode 100644 index b4251b6f7..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-portal.svelte +++ /dev/null @@ -1,27 +0,0 @@ - - -{#if asChild} - -{:else} - - - -{/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-title.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-title.svelte deleted file mode 100644 index f4780ce2e..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-title.svelte +++ /dev/null @@ -1,35 +0,0 @@ - - -{#if asChild} - -{:else} - - - -{/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-trigger.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-trigger.svelte deleted file mode 100644 index 1a5c8a782..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog-trigger.svelte +++ /dev/null @@ -1,38 +0,0 @@ - - -{#if asChild} - -{:else} - - - -{/if} diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog.svelte b/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog.svelte deleted file mode 100644 index 0ad345297..000000000 --- a/packages/bits-ui/src/lib/bits/alert-dialog/components/alert-dialog.svelte +++ /dev/null @@ -1,61 +0,0 @@ - - - diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/index.ts b/packages/bits-ui/src/lib/bits/alert-dialog/index.ts index 8c0dea558..a03ecccc7 100644 --- a/packages/bits-ui/src/lib/bits/alert-dialog/index.ts +++ b/packages/bits-ui/src/lib/bits/alert-dialog/index.ts @@ -1,15 +1,15 @@ -export { default as Root } from "./components/alert-dialog.svelte"; -export { default as Title } from "./components/alert-dialog-title.svelte"; -export { default as Action } from "./components/alert-dialog-action.svelte"; +export { default as Root } from "$lib/bits/dialog/components/dialog.svelte"; +export { default as Title } from "$lib/bits/dialog/components/dialog-title.svelte"; +export { default as Action } from "$lib/bits/dialog/components/dialog-close.svelte"; export { default as Cancel } from "./components/alert-dialog-cancel.svelte"; -export { default as Portal } from "./components/alert-dialog-portal.svelte"; +export { default as Portal } from "$lib/bits/utilities/portal/portal.svelte"; export { default as Content } from "./components/alert-dialog-content.svelte"; -export { default as Overlay } from "./components/alert-dialog-overlay.svelte"; -export { default as Trigger } from "./components/alert-dialog-trigger.svelte"; -export { default as Description } from "./components/alert-dialog-description.svelte"; +export { default as Overlay } from "$lib/bits/dialog/components/dialog-overlay.svelte"; +export { default as Trigger } from "$lib/bits/dialog/components/dialog-trigger.svelte"; +export { default as Description } from "$lib/bits/dialog/components/dialog-description.svelte"; export type { - AlertDialogProps as Props, + AlertDialogRootProps as RootProps, AlertDialogTitleProps as TitleProps, AlertDialogActionProps as ActionProps, AlertDialogCancelProps as CancelProps, @@ -18,7 +18,4 @@ export type { AlertDialogOverlayProps as OverlayProps, AlertDialogTriggerProps as TriggerProps, AlertDialogDescriptionProps as DescriptionProps, - AlertDialogTriggerEvents as TriggerEvents, - AlertDialogActionEvents as ActionEvents, - AlertDialogCancelEvents as CancelEvents, } from "./types.js"; diff --git a/packages/bits-ui/src/lib/bits/alert-dialog/types.ts b/packages/bits-ui/src/lib/bits/alert-dialog/types.ts index 546838692..73bc82bdf 100644 --- a/packages/bits-ui/src/lib/bits/alert-dialog/types.ts +++ b/packages/bits-ui/src/lib/bits/alert-dialog/types.ts @@ -1,104 +1,26 @@ -import type { HTMLButtonAttributes } from "svelte/elements"; -import type { CreateDialogProps as MeltDialogProps } from "@melt-ui/svelte"; -import type { CustomEventHandler } from "$lib/index.js"; -import type { - DOMElement, - Expand, - HTMLDivAttributes, - HTMLHeadingAttributes, - OmitOpen, - OnChangeFn, - SvelteEvent, - Transition, - TransitionProps, -} from "$lib/internal/index.js"; - -export type AlertDialogPropsWithoutHTML = Expand< - OmitOpen> & { - /** - * The open state of the alert dialog. - * You can bind this to a boolean value to programmatically control the open state. - * - * @defaultValue false - */ - open?: boolean; - - /** - * A callback function called when the open state changes. - */ - onOpenChange?: OnChangeFn; - } ->; - -export type AlertDialogTriggerPropsWithoutHTML = DOMElement; - -export type AlertDialogActionPropsWithoutHTML = DOMElement; - -export type AlertDialogCancelPropsWithoutHTML = DOMElement; - -export type AlertDialogContentPropsWithoutHTML< - T extends Transition = Transition, - In extends Transition = Transition, - Out extends Transition = Transition, -> = Expand & DOMElement>; - -export type AlertDialogOverlayPropsWithoutHTML< - T extends Transition = Transition, - In extends Transition = Transition, - Out extends Transition = Transition, -> = Expand & DOMElement>; - -export type AlertDialogDescriptionPropsWithoutHTML = DOMElement; - -export type AlertDialogPortalPropsWithoutHTML = DOMElement; - -export type AlertDialogTitlePropsWithoutHTML = Expand< - { - level?: "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; - } & DOMElement +import type { DialogContentPropsWithoutHTML, DialogContentProps } from "$lib/types.js"; + +export type { + DialogRootPropsWithoutHTML as AlertDialogRootPropsWithoutHTML, + DialogRootProps as AlertDialogRootProps, + DialogClosePropsWithoutHTML as AlertDialogActionPropsWithoutHTML, + DialogCloseProps as AlertDialogActionProps, + DialogClosePropsWithoutHTML as AlertDialogCancelPropsWithoutHTML, + DialogCloseProps as AlertDialogCancelProps, + DialogPortalPropsWithoutHTML as AlertDialogPortalPropsWithoutHTML, + DialogPortalProps as AlertDialogPortalProps, + DialogOverlayPropsWithoutHTML as AlertDialogOverlayPropsWithoutHTML, + DialogOverlayProps as AlertDialogOverlayProps, + DialogTitlePropsWithoutHTML as AlertDialogTitlePropsWithoutHTML, + DialogTitleProps as AlertDialogTitleProps, + DialogDescriptionPropsWithoutHTML as AlertDialogDescriptionPropsWithoutHTML, + DialogDescriptionProps as AlertDialogDescriptionProps, + DialogTriggerPropsWithoutHTML as AlertDialogTriggerPropsWithoutHTML, + DialogTriggerProps as AlertDialogTriggerProps, +} from "$lib/types.js"; + +export type AlertDialogContentPropsWithoutHTML = Omit< + DialogContentPropsWithoutHTML, + "onInteractOutside" >; - -export type AlertDialogProps = AlertDialogPropsWithoutHTML; - -export type AlertDialogTriggerProps = AlertDialogTriggerPropsWithoutHTML & HTMLButtonAttributes; - -export type AlertDialogActionProps = AlertDialogActionPropsWithoutHTML & HTMLButtonAttributes; - -export type AlertDialogCancelProps = AlertDialogCancelPropsWithoutHTML & HTMLButtonAttributes; - -export type AlertDialogContentProps< - T extends Transition = Transition, - In extends Transition = Transition, - Out extends Transition = Transition, -> = AlertDialogContentPropsWithoutHTML & HTMLDivAttributes; - -export type AlertDialogOverlayProps< - T extends Transition = Transition, - In extends Transition = Transition, - Out extends Transition = Transition, -> = AlertDialogContentPropsWithoutHTML & HTMLDivAttributes; - -export type AlertDialogDescriptionProps = AlertDialogDescriptionPropsWithoutHTML & - HTMLDivAttributes; - -export type AlertDialogPortalProps = AlertDialogPortalPropsWithoutHTML & HTMLDivAttributes; - -export type AlertDialogTitleProps = AlertDialogTitlePropsWithoutHTML & HTMLHeadingAttributes; - -export type AlertDialogTriggerEvents = { - click: CustomEventHandler; - keydown: CustomEventHandler; -}; - -export type AlertDialogContentEvents = { - pointerdown: SvelteEvent; - pointerup: SvelteEvent; - pointermove: SvelteEvent; - touchend: SvelteEvent; - touchstart: SvelteEvent; - touchcancel: SvelteEvent; - touchmove: SvelteEvent; -}; - -export type AlertDialogActionEvents = AlertDialogTriggerEvents; -export type AlertDialogCancelEvents = AlertDialogTriggerEvents; +export type AlertDialogContentProps = Omit; diff --git a/packages/bits-ui/src/lib/bits/dialog/dialog.svelte.ts b/packages/bits-ui/src/lib/bits/dialog/dialog.svelte.ts index a90d7e2ea..28b14ddc2 100644 --- a/packages/bits-ui/src/lib/bits/dialog/dialog.svelte.ts +++ b/packages/bits-ui/src/lib/bits/dialog/dialog.svelte.ts @@ -10,6 +10,7 @@ const TRIGGER_ATTR = "data-dialog-trigger"; const OVERLAY_ATTR = "data-dialog-overlay"; const DESCRIPTION_ATTR = "data-dialog-description"; const CLOSE_ATTR = "data-dialog-close"; +const CANCEL_ATTR = "data-dialog-cancel"; type DialogRootStateProps = WritableBoxedValues<{ open: boolean; @@ -25,6 +26,7 @@ class DialogRootState { titleId = $derived(this.titleNode ? this.titleNode.id : undefined); triggerId = $derived(this.triggerNode ? this.triggerNode.id : undefined); descriptionId = $derived(this.descriptionNode ? this.descriptionNode.id : undefined); + cancelNode = $state(null); constructor(props: DialogRootStateProps) { this.open = props.open; @@ -64,6 +66,10 @@ class DialogRootState { return new DialogCloseState(props, this); } + createCancel(props: AlertDialogCancelStateProps) { + return new AlertDialogCancelState(props, this); + } + sharedProps = $derived.by( () => ({ @@ -279,6 +285,43 @@ class DialogOverlayState { ); } +type AlertDialogCancelStateProps = WithRefProps; + +class AlertDialogCancelState { + #id: AlertDialogCancelStateProps["id"]; + #ref: AlertDialogCancelStateProps["ref"]; + #root: DialogRootState; + + constructor(props: AlertDialogCancelStateProps, root: DialogRootState) { + this.#id = props.id; + this.#ref = props.ref; + this.#root = root; + + useRefById({ + id: this.#id, + ref: this.#ref, + condition: () => this.#root.open.value, + onRefChange: (node) => { + this.#root.cancelNode = node; + }, + }); + } + + #onclick = () => { + this.#root.closeDialog(); + }; + + props = $derived.by( + () => + ({ + id: this.#id.value, + [CANCEL_ATTR]: "", + onclick: this.#onclick, + ...this.#root.sharedProps, + }) as const + ); +} + const [setDialogRootContext, getDialogRootContext] = createContext("Dialog.Root"); export function useDialogRoot(props: DialogRootStateProps) { @@ -308,3 +351,7 @@ export function useDialogDescription(props: DialogDescriptionStateProps) { export function useDialogClose(props: DialogCloseStateProps) { return getDialogRootContext().createClose(props); } + +export function useAlertDialogCancel(props: AlertDialogCancelStateProps) { + return getDialogRootContext().createCancel(props); +} diff --git a/packages/bits-ui/src/lib/internal/index.ts b/packages/bits-ui/src/lib/internal/index.ts index be1296462..c267e7bcb 100644 --- a/packages/bits-ui/src/lib/internal/index.ts +++ b/packages/bits-ui/src/lib/internal/index.ts @@ -13,7 +13,7 @@ export * from "./context.js"; export * from "./box.svelte.js"; export * from "./useStateMachine.svelte.js"; export * from "../bits/utilities/presence-layer/usePresence.svelte.js"; -export * from "./useNodeById.svelte.js"; +export * from "./useRefById.svelte.js"; export * from "./afterTick.js"; export * from "./locale.js"; export * from "./elements.js"; diff --git a/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte b/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte index 25957237b..2f6884904 100644 --- a/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte +++ b/sites/docs/src/lib/components/demos/alert-dialog-demo.svelte @@ -1,7 +1,5 @@ @@ -14,13 +12,10 @@