Skip to content

Commit

Permalink
fix: dialog buttons not responding on certain mobile platforms (#937)
Browse files Browse the repository at this point in the history
  • Loading branch information
huntabyte authored Nov 16, 2024
1 parent d04fb6b commit ffc5db7
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 83 deletions.
5 changes: 5 additions & 0 deletions .changeset/sixty-panthers-fetch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"bits-ui": patch
---

fix: Dialog buttons not responding on certain mobile platforms
63 changes: 33 additions & 30 deletions packages/bits-ui/src/lib/bits/dialog/dialog.svelte.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useRefById } from "svelte-toolbelt";
import type { KeyboardEventHandler, MouseEventHandler, PointerEventHandler } from "svelte/elements";
import { getAriaExpanded, getDataOpenClosed } from "$lib/internal/attrs.js";
import type { ReadableBoxedValues, WritableBoxedValues } from "$lib/internal/box.svelte.js";
import { createContext } from "$lib/internal/create-context.js";
Expand Down Expand Up @@ -88,7 +89,13 @@ class DialogTriggerState {
});
}

#onpointerdown = (e: PointerEvent) => {
#onclick: MouseEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.button > 0) return;
this.#root.handleOpen();
};

#onpointerdown: PointerEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") return e.preventDefault();
if (e.button > 0) return;
Expand All @@ -99,15 +106,7 @@ class DialogTriggerState {
this.#root.handleOpen();
};

#onpointerup = (e: PointerEvent) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") {
e.preventDefault();
this.#root.handleOpen();
}
};

#onkeydown = (e: KeyboardEvent) => {
#onkeydown: KeyboardEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
e.preventDefault();
Expand All @@ -125,7 +124,7 @@ class DialogTriggerState {
[this.#root.attrs.trigger]: "",
onpointerdown: this.#onpointerdown,
onkeydown: this.#onkeydown,
onpointerup: this.#onpointerup,
onclick: this.#onclick,
...this.#root.sharedProps,
}) as const
);
Expand Down Expand Up @@ -158,22 +157,24 @@ class DialogCloseState {
});
}

#onpointerdown = (e: PointerEvent) => {
#onclick: MouseEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") return e.preventDefault();
if (e.button > 0) return;
this.#root.handleClose();
};

#onpointerup = (e: PointerEvent) => {
#onpointerdown: PointerEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") {
e.preventDefault();
this.#root.handleClose();
}
if (e.pointerType === "touch") return e.preventDefault();
if (e.button > 0) return;
// by default, it will attempt to focus this trigger on pointerdown
// since this also opens the dialog we want to prevent that behavior
e.preventDefault();

this.#root.handleClose();
};

#onkeydown = (e: KeyboardEvent) => {
#onkeydown: KeyboardEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
e.preventDefault();
Expand All @@ -187,7 +188,7 @@ class DialogCloseState {
id: this.#id.current,
[this.#attr]: "",
onpointerdown: this.#onpointerdown,
onpointerup: this.#onpointerup,
onclick: this.#onclick,
onkeydown: this.#onkeydown,
...this.#root.sharedProps,
}) as const
Expand Down Expand Up @@ -398,24 +399,26 @@ class AlertDialogCancelState {
});
}

#onpointerdown = (e: PointerEvent) => {
#onclick: MouseEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") return e.preventDefault();
if (e.button > 0) return;
this.#root.handleClose();
};

#onkeydown = (e: KeyboardEvent) => {
#onpointerdown: PointerEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
e.preventDefault();
this.#root.handleClose();
}
if (e.pointerType === "touch") return e.preventDefault();
if (e.button > 0) return;
// by default, it will attempt to focus this trigger on pointerdown
// since this also opens the dialog we want to prevent that behavior
e.preventDefault();

this.#root.handleClose();
};

#onpointerup = (e: PointerEvent) => {
#onkeydown: KeyboardEventHandler<HTMLButtonElement> = (e) => {
if (this.#disabled.current) return;
if (e.pointerType === "touch") {
if (e.key === kbd.SPACE || e.key === kbd.ENTER) {
e.preventDefault();
this.#root.handleClose();
}
Expand All @@ -427,7 +430,7 @@ class AlertDialogCancelState {
id: this.#id.current,
[this.#root.attrs.cancel]: "",
onpointerdown: this.#onpointerdown,
onpointerup: this.#onpointerup,
onclick: this.#onclick,
onkeydown: this.#onkeydown,
...this.#root.sharedProps,
}) as const
Expand Down
2 changes: 1 addition & 1 deletion sites/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"scripts": {
"dev": "concurrently \"pnpm:dev:content\" \"pnpm:dev:svelte\" \"pnpm:replace:velite\"",
"dev:content": "velite dev --watch",
"dev:svelte": "vite dev",
"dev:svelte": "vite dev --host",
"build": "velite && node ./other/update-velite-output.js && pnpm build:search && vite build",
"replace:velite": "node ./other/watch-velite-output.js",
"build:content": "velite",
Expand Down
50 changes: 4 additions & 46 deletions sites/docs/src/lib/components/ui/sheet/index.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { Dialog as SheetPrimitive } from "bits-ui";
import { type VariantProps, tv } from "tailwind-variants";

import Content from "./sheet-content.svelte";
import Description from "./sheet-description.svelte";
import Footer from "./sheet-footer.svelte";
import Header from "./sheet-header.svelte";
import Overlay from "./sheet-overlay.svelte";
import Title from "./sheet-title.svelte";

const Root = SheetPrimitive.Root;
const Close = SheetPrimitive.Close;
const Trigger = SheetPrimitive.Trigger;
const Portal = SheetPrimitive.Portal;
const Root = SheetPrimitive.Root as typeof SheetPrimitive.Root;
const Close = SheetPrimitive.Close as typeof SheetPrimitive.Close;
const Trigger = SheetPrimitive.Trigger as typeof SheetPrimitive.Trigger;
const Portal = SheetPrimitive.Portal as typeof SheetPrimitive.Portal;

export {
Close,
Expand All @@ -36,43 +34,3 @@ export {
Title,
Trigger,
};

export const sheetVariants = tv({
base: "fixed z-50 gap-4 bg-background p-6 shadow-lg",
variants: {
side: {
top: "inset-x-0 top-0 border-b ",
bottom: "inset-x-0 bottom-0 border-t",
left: "inset-y-0 left-0 h-full w-3/4 border-r sm:max-w-sm",
right: "inset-y-0 right-0 h-full w-3/4 border-l sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
});

export const sheetTransitions = {
top: {
y: "-100%",
duration: 500,
opacity: 1,
},
bottom: {
y: "100%",
duration: 500,
opacity: 1,
},
left: {
x: "-100%",
duration: 500,
opacity: 1,
},
right: {
x: "100%",
duration: 500,
opacity: 1,
},
};

export type Side = VariantProps<typeof sheetVariants>["side"];
34 changes: 28 additions & 6 deletions sites/docs/src/lib/components/ui/sheet/sheet-content.svelte
Original file line number Diff line number Diff line change
@@ -1,21 +1,43 @@
<script lang="ts" module>
import { type VariantProps, tv } from "tailwind-variants";
export const sheetVariants = tv({
base: "fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
variants: {
side: {
top: "inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top",
bottom: "inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom",
left: "inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm",
right: "inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm",
},
},
defaultVariants: {
side: "right",
},
});
export type Side = VariantProps<typeof sheetVariants>["side"];
</script>

<script lang="ts">
import { Dialog as SheetPrimitive } from "bits-ui";
import { Dialog as SheetPrimitive, type WithoutChildrenOrChild } from "bits-ui";
import X from "phosphor-svelte/lib/X";
import type { Snippet } from "svelte";
import { SheetOverlay, SheetPortal, type Side, sheetVariants } from "./index.js";
import SheetOverlay from "./sheet-overlay.svelte";
import { cn } from "$lib/utils/index.js";
let {
side,
side = "right",
class: className,
children,
...restProps
}: Omit<SheetPrimitive.ContentProps & { side?: Side }, "child" | "children" | "ref"> & {
}: WithoutChildrenOrChild<SheetPrimitive.ContentProps> & {
children?: Snippet;
side?: Side;
} = $props();
</script>

<SheetPortal>
<SheetPrimitive.Portal>
<SheetOverlay />
<SheetPrimitive.Content class={cn(sheetVariants({ side }), className)} {...restProps}>
{@render children?.()}
Expand All @@ -26,4 +48,4 @@
<span class="sr-only">Close</span>
</SheetPrimitive.Close>
</SheetPrimitive.Content>
</SheetPortal>
</SheetPrimitive.Portal>

0 comments on commit ffc5db7

Please sign in to comment.